I am new to Mongoose and getting my head around populations. I have Schema that looks like...
var ProjectSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Project name',
trim: true
},
created: {
type: Date,
default: Date.now
},
topics: [{
type: Schema.ObjectId,
ref: 'Topic'
}]
});
When I am querying for projects I use .populate('topics') and it works fine. When the project is populated the topics property holds actual objects rather than references.
P.S. The Topic does not have a project reference (I found it difficult to maintain resiprocal relations in MongoDB).
My question is: when I want to add a topic object to a project. Do I add the ObjectId or the object itself?
I saw this question and an answer given but I didn't think it really explained what you asked, so I thought something was worthwile here.
As is demonstrated in the supplied schema, the "topics" property is a "referenced array" which basically means it is going to hold a "reference" ( or essentially an
ObjectId
value ) to the document that lies in another collection. The mongoose "schema" definition is what ties this to the "associated" model where that object resides, as you should know.The question posed is "do I push the object, or do I just push the
_id
value", which in itself raises some questions about "what do you really want to do here?".For that last, take the following code example ( presuming model and schema are all defined ):
So as per the comment in the code there, mongoose actually only adds the "_id" value into the parent document even though you asked it to "push" the entire "object". It just works out "that is what you meant to do" via the presented schema interface to the model. Not hard to do in code really, but just so you understand the underlying mechanics.
You can alternately "just use the
_id
value" from the object created ( after it is saved best for safety ) and add that to the array by similar means. It is much the same result:That method is all well and fine, provided of course that by some form or other you actually have the "Objects in memory" at the time of processing for both
Project
andTopic
with appropriate data.On the other hand, let us presume that
Project
represents an object that lies in the collection, and though you know it's_id
value or other "unique" representing property, that object data has not actually been loaded from the database via.findOne()
type of operation or similar.Let us then assume that you have none of the
Project
model data resident in memory. So how to add your new topic?This is where the native operators for MongoDB come into play. Particularly there is
$push
which is of course analogous to the.push()
array operator in JavaScript but with a particular "Server Side" action.As stated earlier, you do not have the
Project
model data loaded, but you wish to modify a particularProject
item in storage by "pushing" the desiredTopic
object to something defined in yourProject
object's collection by it's identifier:The "update" mechanics can be
.findOneAndUpdate()
or even.findByIdAndUpdate()
as you find appropriate ( those methods both return the modifed object by default where.update()
does not ) to what you want to achieve as a result of your operation here.The main difference to the previous approaches is that since the object for
Project
that is to be modifed does not reside in memory for your application code then you use these methods to just modify it on the server instead. This can be a "good thing" as you do not need to "load" that data just to make a modification. The MongoDB operators allow you to$push
the array content without loading first.That approach is acutally your best approach for "concurrent updates" with high transaction systems. The reason being that there is "no guarantee" that in between a
.findOne()
or similar operation in your application and the modifications with the eventual.save()
action that "no data has been changed" on the server storage between those actions occurring.The
$push
operator "ensures" that the data modified on the server remains "as it was" at the time of execution with of course the addition of the new data you added to the array.The other obvious thing here is that since the operation is using a native MongoDB operator to achieve this effiency, the mongoose Schema rules are bybassed. So you cannot of course just "push" the entire "topic" object into the array, without of course ending up with an "entire" topic object in storage:
That is essentially the difference between, "adding an object reference" to an array and "adding an 'Object' to an array". It depends on the methods used and the "efficiency" methods you actually choose.
Hope this is useful to yourself and those others who might stumble upon the same topic you raised.