Coerce Moment/Date to string with AJV - ajv

How can I coerce an json object that uses moment/date for date fields into a schema that uses
{type: "string", format: "date-time"} with AJV?
I've tried using a custom keyword, but this doesn't run if the data is not a string.
{
myDate: moment()
}
Should convert to
{
myDate: "2012-04-23T18:25:43.511Z"
}

Related

Change int datatype to string in mongodb

I am trying to change int to string in mongodb for CardNumber.The script shows executed successfully but datatype does not change.Please let me know how to resolve this issue.
GiftCardSale
[0]CardNumber
Amount
[1]CardNumber
Amount
db.SalesOrder2.find({"GiftCardSale.$[i].CardNumber": {$exists:true}}).sort({_id:1}).skip(0).limit(100)
.forEach( function(x) {
db.SalesOrder2.update({_id: x._id}, {$set: {"GiftCardSale.$[i].CardNumber":
x.GiftCardSale.$[i].CardNumber.toString()}});
}
);
To change multiple fields data types in mongodb:
In this case we are changing fields data type from int to string.
1.login mongo shell(mongosh) with the database address
2.type mongosh command: show dbs to look up your database
3.type mongosh command: use to select the database you want to update with
4.type in like below:
db.<dbname>.updateMany(
{ <field> : { $type: 16 } },
[{ $set: { <field>: { $toString: "$<field>" } } }]
)
5.bingo!
PS: All the variables/fields in angle brackets, AKA within "" should be replaced with your actual variable/field name for example that would become:
db.mydatabase.updateMany(
{ myfield : { $type: 16 } },
[{ $set: { myfield: { $toString: "$myfield" } } }]
)
For other cases, simply change the function from "toString" to other functions you want. Also if you want to match the input field type with other format such as string, you will need to change $type: 16 to $type: 1
For specific type number matching(with an awesome graph demonstration), checkout below https://data-flair.training/blogs/mongodb-data-types/

Filter react-admin query by dates

I am using react-admin's useGet... query to gather data from my rails backend. The main problem here is the filter property (the last pair of curly braces in the useGetList operation). How can i filter the data by Dates (like get only transactions of the last month etc.)
This is the current (working) approach:
const { data, loading, error } = useGetList(
'transactions',
{ page: 1, perPage: 10000 },
{ field: 'id', order: 'ASC' },
{},
)
if (loading) return <p>Loading</p>
if (error) return <p>Error</p>
if (!data) return null
The entries in the database all have a createdAt and updatedAt property.
My approach would be to create a filter like this:
// constraints could be dates that I can easily set beforehand
{
{'createdAt', desiredLowerTimeConstraint, operation: '<='},
{'createdAt', desiredUpperTimeConstraint, operation: '<='}
}
The react-admin documentation is quite sparce with the filter property, I couldn't find good examples for how these objects are supposed to look like.
It all depends on how your API expects filters to look like.
For instance, in REST APIs served by JSONServer, a _lte suffix on a query string parameter name indicates that you want results "Less Than or Equal to" the value:
GET /transactions?createdAt_lte=2019-12-05
Provided you use the ra-data-simple-rest, you can craft this request by passing the parameter in the filter:
const { data, loading, error } = useGetList(
'transactions',
{ page: 1, perPage: 10000 },
{ field: 'id', order: 'ASC' },
{ createdAt_lte: '2019-12-05' },
)
If your API behaves differently, then you may use the same syntax for useGetList, and transform the parameter in your dataProvider before it's sent to the API.

Pushing onto Mongo SubDoc of SubDoc array

I'm going around in circles with this one so hoping someone can help. I'm building a nodejs application that receives sensor values from nodes. There can be multiple sensors on a node.
Using NodeJS, Mongod DB and Mongoose, all running on a raspberry pi, 3 I've built the following Schemas & Model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var valueSchema = new Schema ({
timestamp: {type: Date},
value: {}
});
var sensorSchema = new Schema ({
id: {type: Number},
type: {type: String},
description: {type: String},
ack: {type: Boolean},
values: [valueSchema]
});
var SensorNode = mongoose.model('SensorNode', {
id: {type: Number, required: true},
protocol: {},
sensors: [sensorSchema]
});
I can add in the node, and push sensors onto the sensors array, but I seem unable to push values onto the values array.
I've looked over a few other examples and questions on similar issues, and looked at using populate, but cant seem to get them to work.
Here is my code:
function saveValue(rsender, rsensor, payload) {
var value = {
values: {
timestamp: new Date().getTime(),
value: payload
}
}
SensorNode.findOneAndUpdate({
"id": rsender,
"sensors.id": rsensor
}, {
"$push": {
"sensors.$": value
}
}, function(err, result) {
if (err) {
console.log(err);
}
console.log(result);
});
}
This is returning undefined for the result and this error:
MongoError: exception: Cannot apply $push/$pushAll modifier to non-array
Values is definitely an array in the sensor schema.
I'm using readable ids rather than the auto assigned Mongo DB IDs for the sake of the UI, but I could use the MongoDB _id if that makes any difference, I don't see why it would?
Where am I going wrong ?
You're using positional operator $ so let's check the docs
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array. To project, or return, an array element from a read operation, see the $ projection operator.
So sensors.$ will return one particular document from your sensors array. That's why you're getting an error. On this level of your document you can only replace this item by using $set. I bet you wanted to do something like this:
SensorNode.findOneAndUpdate({
"id": rsender,
"sensors.id": rsensor
}, {
"$push": {
"sensors.$.values": payload
}
});
This operation will just append payload to values array in one particular sensor with id equal to rsensor.

mongoose query: find an object by id in an array

How could I find an image by id in this Schema. I have the id of the User and the id of the image I am looking for. What would be the best way to do this and do all images in this case have different ids or could they have the same id because they don't belong to the same User?
My Schema looks like this:
var userSchema = new Schema({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
name: String,
about: String,
images: [{
id: Schema.ObjectId,
link: String,
main: Boolean
}]
});
When you are interested in the full object it is a simple find:
.find({"facebook.id":"<id>", "images.id":<image-id>})
I don't think that there is a way to reduce the image array in the result.
To update a single element in the image array you can use this:
.update({"facebook.id":"<id>", "images.id":<image-id>}, {$set : {"images.$.main" :false} } );
userSchema .find({facebook.id: "some ID",{ "images.id": { $in: [ id1, id2, ...idn] }}
since images are inside the document you can have same ID's however every time you query you should keep in mind that you send some other parameters such as facebook.id or facebook.email along with image id's to retrieve them. Otherwise you end up getting all that might be irrelevant only because you decide to keep same ID's for images.
tl;dr
I struggled with this and came up with a solution. Like you, I was trying to query for a deeply nested object by the _id, but I kept coming up empty with the results. It wasn't until I did some type checking that I realized the id value I was getting from my frontend, while directly supplied by mongoose, was in fact a String and not an Object.
I realize this question was already partially answered before, but that person's solution didn't work for me, and the comment on the answer tells me you wanted to update the specific image you queried for, which is exactly what I was trying to do.
The solution
In order to select an object from the nested array by the _id value, first you'll have to install the npm package bson-objectid and use the provided method to convert your string into an objectId in your query.
In your terminal:
npm i bson-objectid
In your code:
const ObjectId = require('bson-objectid')
userSchema.findOneAndUpdate(
{ "facebook.id": <user-id>, "images._id": ObjectId(<image-id>) },
{ "$set": { "images.$.main": false } },
{ new: true }, // an extra options parameter that returns the mutated document
(err, user) => {
if (err) {
handleErr(err)
} else {
console.log(user)
// do something with new user info
}
)

Unique array values in Mongoose

Currently trailing out Mongoose and MongoDB for a project of mine but come across a segment where the API is not clear.
I have a Model which contains several keys and documents, and one of those keys os called watchList. This is an array of ID's that the user is watching, But I need to be sure that these values stay unique.
Here is some sample code:
var MyObject = new Mongoose.Schema({
//....
watching : {type: Array, required: false},
//....
});
So my question is how can I make sure that the values pushed into the array only ever store one, so making the values unique, can i just use unique: true ?
Thanks
To my knowledge, the only way to do this in mongoose is to call the underlying Mongo operator (mentioned by danmactough). In mongoose, that'd look like:
var idToUpdate, theIdToAdd; /* set elsewhere */
Model.update({ _id: idToUpdate },
{ $addToSet: { theModelsArray: theIdToAdd } },
function(err) { /*...*/ }
);
Note: this functionality requires mongoose version >= 2.2.2
Take a look at the Mongo documentation on the $addToSet operator.
Mongoose is an object model for mongodb, so one option is to treat the document as a normal javascript object.
MyModel.exec(function (err, model) {
if(model.watching.indexOf(watchId) !== -1) model.watching.push(watchId);
model.save(...callback);
});
Although, I do agree that mongoose should have some support for this built in the form of a validator for the collection document reference feature-- especially because most of the time you want to add only unique references.
That's how you can do it using Mongoose,
IF your upcoming value is an Array
Model
.findOneAndUpdate({ _id: yourID },
{ $addToSet: { watching: { $each: yourWatchingArr } } },
function(err) { /*...*/ }
);
IF your upcoming value is a string
Model
.findOneAndUpdate({ _id: yourID },
{ $addToSet: { watching: yourStringValue } },
function(err) { /*...*/ }
);

Resources