Mongoose: retrieving array of ObjectIds from collection - node.js

My database has following type of documents for Categories collection.
{
"_id" : ObjectId("56716afa403743492828aa07"),
"cat_name" : "watches",
"cat_parent_id" : [
ObjectId("56716afa403743492828aa01"),
ObjectId("56716afa403743492828aa03")
]
.........
}
I first created database with Robomongo, then I'm trying to fetch data using mongoose and created following Schema.
var categorySchema = new Schema({
'cat_name' : String,
'cat_parent_id' : [{ type : mongoose.Types.ObjectId }],
.......
});
but when I'm getting the result through following callback,
Categories.find(function(err,categories){........});
the cat_parent_id array is empty.
Edit:
When I replace mongoose.Types.ObjectId with Schema.Types.ObjectId or String,It works.Can anyone provide reason for that?

You need to add reference for the ObjectId type:
var categorySchema = new Schema({
'cat_name' : String,
'cat_parent_id' : [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Categories'
}],
.......
});

Related

Mongoose query to check for specific value in array of searched element

I have s schema like:
var EntitySchema = new Schema({
name : {type: String, default: null},
organizations : [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Organization'
}}]
});
I have an id of organization, How can I make a query for Entity.find({}) and find Entity that has this id in its organizations array?
I used this in mongo shell
db.entity.find({"organizations.id": { $in: [ObjectId("ididididididid")]}}).pretty()
and it worked, but it doesn't work in express method, do I do something wrong? Does $in works both ways? I have a feeling that its not what I should be using in this query.
As per mongo documentation, you can query as below
db.entity.find({ "organizations" : { $elemMatch: { "id" : ObjectId("ididididididid") } }}).pretty();
Ref:
https://docs.mongodb.com/manual/tutorial/query-array-of-documents/

Mongoose, CastError: Cast to Array failed for value when trying to save a model that contains a model

I am trying to create the model for my mongodb database using mongoose. This is what I am trying to do:
var Class = mongoose.model('Class', {className: String, marks: [{type: Number}], grades: [{type: Number}]});
var User = mongoose.model('User', {email: String, classes: [Class] });
//Lets create a new user
var class1 = new Class({className: 'aaa', marks: [72, 88, 63], grades: [30, 40, 30]});
var user1 = new User({email: 'aaa#some.com', classes: [class1]});
Saving class1 seems to work okay but when I check mongodb, this is displayed:
{
"_id" : ObjectId("someId"),
"className" : "TEST1234",
"grades" : [ 30, 40, 30 ],
"marks" : [ 72, 88, 63 ],
"__v" : 0
}
What is "__v : 0"?
Saving the user is not successful at all, this is the following error:
ValidationError: CastError: Cast to Array failed for value "{ marks: [ 72, 88, 63 ],
grades: [ 30, 40, 30 ],
_id: someId,
className: 'TEST1234' }" at path "classes"
`
What exactly does the error mean? Why is it casting anything to a array? Shouldn't classes: [Class] be an array of type class?
Man, I had a similar issue creating an Schema like this:
QuestionnaireSchema = mongoose.Schema({
formId: Number,
name: String,
questions: [
{
type: String,
title: String,
alternatives:[{
label: String,
value: "Mixed"
}]
}
]
});
My mistake was that I am using "type" as a field name and this is reserved word in mongoose.
I just change:
type: String,
to
formType: String,
and that works.
see: https://github.com/Automattic/mongoose/issues/1760
Explicitly defining the type rule on a property called type is allowed and won't throw an error. like this:
type: {type: String}
Try changing the class definition to :
var classSchema = mongoose.Schema({className: String, marks: [{type: Number}], grades: [{type: Number}]});
var userSchema = mongoose.Schema({email: String, classes: [classSchema] });
var User = mongoose.model('User',userSchema);
This is required since mongoose is not able to parse the object without a related schema. Now when you create a new Schema for the internal class object and refer it in the main userSchema mongoose should be able to parse your object.
Your model definition is incorrect, you should fix like below.
// var Schema = mongoose.Schema;
var User = mongoose.model('User',{
email: String,
classes: [ {type: Schema.Types.ObjectID, ref: 'Class'}]
});
var Class1 = new Class({/*yourDataWillBeHere*/})
Class1.save(function(err, classData) {
var User1 = new User({/*YourDataWillBeHere*/})
User1.classes.push(classData._id);
User1.save(function(err, userData) {
//make something with userData object
})
})
Then you can get fetched data using with populate() like this
User
.find()
.populate('classes')
.exec()
By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration.
// Mongoose interprets this as 'loc is a String'
var schema = new Schema({ loc: { type: String, coordinates: [Number] } });
Changing the typeKey:
var schema = new Schema({
// Mongoose interpets this as 'loc is an object with 2 keys, type and coordinates'
loc: { type: String, coordinates: [Number] },
// Mongoose interprets this as 'name is a String'
name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration
Link: http://mongoosejs.com/docs/guide.html#typeKey
Just for Update
Now Mongoose supports subdocuments, which are the documented way to nest arrays,
var arraySchema = new Schema({
property: String
});
var objectSchema = new Schema({
arrays: [arraySchema]
});
Sources
http://mongoosejs.com/docs/schematypes.html
I got a similar issue using mongoose 5.7.0+ using double nested schema.
Except it wasn't related to the keyword type but a mongoose validation bug.
https://github.com/Automattic/mongoose/issues/8472
Temporary workaround: Use Schema.Types.Mixed for the subschema

Mongoose schema updating GeoJSON

I have the following Mongoose schema representing a moving object
var vehicleSchema = new Schema({
properties:{
obj:String,
name:String,
id:String
},
geometry : {
type: {type : String},
coordinates : [ Number, Number ]
}
});
and I am trying to update it with the following object and command which work flawlessly if I enter in mongo console but does not update the document when used in a node function.
This is the object to be updated:
var updatedVehicle = new Vehicle(
{properties:{
obj:"Answer",
name:"is",
id:"42"
},
geometry:{
type:"Point",
coordinates:[42,42]
}
})
And this is the update command
Vehicle.update(
{$and:[
{'properties.obj':data.properties.obj},
{'properties.id':data.properties.id}
]},
{$set:
{properties:data.properties, geometry:data.geometry}
},
{upsert: true},
cb
)
I know that Mongoose has some quirks when it comes to GeoJSON and I hope this is just another one.
Your geometry schema property should just be set to an array of Numbers to store the coordinates, like so:
geometry : {
type: [Number],
index: '2dsphere` //some geospatial queries require this
}
and then query and updated as such
{ $set: { geometry: data.geometry.coordinates } }

How to populate array of objects with Mongoose

I have the following schemas in mongoose:
var documentsSchema = new Schema({
"document" : {
"_project" : {
type : Schema.ObjectId,
ref : 'Projects'
},
"_addedBy" : {
type : Schema.ObjectId,
ref : 'Users'
},
"_associateUsers" : [{
type : Schema.ObjectId,
ref : 'Users'
}],
"_codes" : [{
type : Schema.ObjectId,
ref : 'Codes'
}],
"paragraphTitle" : String,
"paragraphText" : String,
"memos" : [
{
"_addedBy" : {
type: Schema.Types.ObjectId,
ref: 'Users'
},
"memoData" : String
}
]}});
and the Codes:
var codesSchema = new Schema({
"code" : {
"_addedBy" : {
type : Schema.ObjectId,
ref : 'Users'
},
"codeText" : String,
"codeWeight" : Number
}});
I need to populate _codes.codeText (or codes fields) of the all elements of the array, but looks like I am not doing it properly.
Documents.find({
"document._project": element._id
}).
populate('document._codes.code','codeText').
exec(function (err, result) { .... }
this and various tries with populate arguments are either not populating the fields or not returning any data.
What am I doing wrong?
You have defined the schema, but not the model. The _codes has a ref to the model Codes but it doesn't exists. When you call .populate with the first two params it assumes that the model is Codes (taked from reference)
To fix this, toy need to add:
mongoose.model('Codes', codesSchema);
mongoose.model('Documents', documentsSchema);
Maybe you need to do the same with Users
See the complete documentation for populate here
P.S. A recommendation: If you are defining an schema for codes or whatever you don't need to define again the name of the object as part of the same schema, look:
From this
//your style
var catsSchema = new Schema({
"cat" : {
"attr1" : {type: ...},
"attr2" : {type: ...}
}
});
to this
//obviously attr1 and attr2 are part of cat object/document
var catsSchema = new Schema({
"attr1" : {type: ...},
"attr2" : {type: ...}
});

Mongo: query on subdocs

Hello I have this problem when checking if a subdocument exist before pushing a new subdocument.
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String,
tasks : [{type: Schema.ObjectId, ref: 'Task'}] // assuming you name your model Task
});
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {type: Schema.ObjectId, ref: 'User'} // assuming you name your model User
});
With this, your query for all users, including arrays of their tasks might be:
User.findOne({...}).populate('tasks').run(function(err, user) {
var subdoc = user.tasks.id(mytask.id);
if(subdoc){
//not exist
//push
}
});
This is the error:
TypeError: Object has no method 'id'
You are getting that error because there is no 'id' field defined for the 'tasks' subdocument. You might have meant 'user.tasks._id', which will return the ObjectId that MongoDB adds to its documents by default.

Resources