Reputation: 6117
As the Mongoose - Subdocs: "Adding subdocs" documentation says, we can add a subdoc using the push
method (i.e. parent.children.push({ name: 'Liesl' });
)
But I want to go further, and would like to use the $push
operator to insert subdocuments.
I have two Schemas: the ThingSchema
:
var ThingSchema = mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String
}
});
and the BoxSchema
, the main document that has an array of subdocuments (things
) of ThingSchema
:
var BoxSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String
},
things: {
type: [ThingSchema]
}
});
var BoxModel = mongoose.model('Box', BoxSchema);
I need every subdocument in things
to have unique
names - that is, that it would be impossible to insert a new document into this array that has a name
value that already exists in the subdocs.
I'm trying to do something like:
var thingObj = ... // the 'thing' object to be inserted
BoxModel.update({
_id: some_box_id, // a valid 'box' ObjectId
"things.name": { "$ne": thingObj.name }
},
{
$push: { things: thingObj}
},
function(err) {
if (err) // handle err
...
});
but not getting any desired results.
What would be the correct way to add a ThingSchema
subdocument into BoxSchema
's thing
array using the $push
operator to do so in the query (must not add the subdoc if there's another subdoc named the same), instead of the Mongoose Docs way?
I made a mistake, the code above works as expected but now the problem I have is that when thingObj
does not match the ThingSchema
, an empty object is inserted into the things
array:
// now thingObj is trash
var thingObj = { some: "trash", more: "trash" };
When executing the query given the above trash object, the following empty object is inserted into the subdocs array:
{ _id: ObjectId("an_obj_id") }
What I want this case, when the thingObj
doesn't match the ThingSchema
, is nothing to be added.
Upvotes: 2
Views: 814
Reputation: 374
$addToSet
adds something unique to the array (as in it checks for duplicates). But it only works for primitives.
What you should do is put things
into their own collection and make a unique index on name. Then, make this change
things: {
type: [{type: ObjectId, ref: 'thingscollection'}]
}
this way you can do
BoxModel.update({
_id: some_box_id, // a valid 'box' ObjectId
"things": { "$ne": thingObj._id }
},
{
$addToSet: { things: thingObj._id}
},
function(err) {
if (err) // handle err
...
});
And when you fetch use .populate
on things
to get the full documents in there.
It's not exactly how you want it, but that's a design that might achieve what you're aiming for.
Upvotes: 1