Reputation: 123
I have the following data structure in Mongo:
{
"_id": "L7ucxMsTSfTDtctnt",
"lectures": [
{
"_id": "Tfr3DMxavZwP5yy6F",
"notes": [
{
"slide": 1,
"notes": "First Note",
"timestamp": "2015-05-18T20:18:36.510Z"
},
{
"slide": 2,
"notes": "Another note",
"timestamp": "2015-05-18T20:18:36.510Z"
}
]
}
]
}
I'm trying to do a triple upsert and an array push. So if the outer _id doesn't exist, create it, otherwise update it. If the lecture _id doesn't exist, create it, otherwise update it. If the notes _id doesn't exist create the object and pushing to to the notes array, otherwise update it.
Is it possible to do something this complicated? I can do it in three separate steps, but I'm calling the function frequently and am worried about performance.
Upvotes: 0
Views: 362
Reputation: 4948
If you could do this in 3 steps, it'd be pretty impressive... Heck, it hurts my brain just trying to write a query to return a single notes object with that schema. (try it, you won't like it).
the array of object pattern starts getting really cumbersome in mongo after the 2nd layer. it's usually preferable to use a new collection or store it as a subdoc (doc.lectures['alsfjljfldjf5084534']
) because then you have a memory address to reference instead of banging your head trying to execute a nested $elemmatch
.
Anyways, to answer your question, it's just 1 upsert, because it's only 1 doc. When you think about the whole thing being 1 doc, it gets easier to wrap your head around. Just fetch the doc & save it as a JS object. Modify the object & then upsert the whole thing. Don't worry about transferring a couple extra bytes of repeated data. Plaguing your database with crazy iterative queries to find the specific point in the doc you want to edit is waaaaaayyyy more taxing.
In this particular case, you've got the ER modeled correctly (1 class has many lectures, 1 lecture has many notes) but, depending on your query patterns, you may want to put classes in their own collection & include the classID as a FK in your lectures collection. Then, optionally make the notes subdocs for easy access.
In doing so, getting a note object is as easy as:
Lectures.findOne({notesID: '234asfj'})
. Sure, you lose atomicity, but it's a small price to pay.
EDIT:
doc = {}; //empty object
subDocId = Random.id(); //ref for subdoc
doc[subDocId] = {
notes: 1,
text: 'foo'
}; // create subdoc
Lecture.insert(doc); //insert subdoc
or
var doc = Lectures.findOne(); //get it
doc["Tfr3DMxavZwP5yy6F"] = {foo:1, bar:2} //mod it
Lecture.insert(doc); //upload it
Upvotes: 2