Reputation: 30956
I have two mongodb collections items and settings.
When documents are inserted into items, one of the fields level needs to be read from the settings table. Currently I'm running two queries to make this happen.
Is there a way to do this as one query like I could do with SQL with select queries inside an insert?
// read
let settingRecord = connection.collection("settings").findOne({
"group_id": 2
}, function(err, result) {});
// write
connection.collection("items").insertOne({
"item_id": 2,
"group_id": 2,
"level": settingRecord['level']
}, function(err, result) {});
Upvotes: 1
Views: 181
Reputation: 334
I could merge into a new collection with a merge command for the given requirement of updating the level field. Let me know how to update the same collection as in aggregate collection eg. items collection in this case.
> db.newCollection.find();
{ "_id" : 1, "groupid" : 2, "itemid" : 2, "settingsDoc" : [ { "level" : 10 } ] }
{ "_id" : 2, "groupid" : 3, "itemid" : 3, "settingsDoc" : [ { "level" : 30 } ] }
> db.items1.find();
{ "_id" : 1, "groupid" : 2, "itemid" : 2, "level" : null }
{ "_id" : 2, "groupid" : 3, "itemid" : 3, "level" : null }
> db.settings.find();
{ "_id" : 1, "groupid" : 2, "level" : 10 }
{ "_id" : 2, "groupid" : 3, "level" : 30 }
> db.items1.aggregate([
... {$lookup:{
... from: "settings",
... localField: "groupid",
... foreignField: "groupid",
... as:"settingsDoc"
... }
... },
... {$project:{
... groupid:1,
... itemid:1,
... "settingsDoc.level":1
... }
... },
... {$merge:{into:"newCollection"}
... }
... ]);
> db.newCollection.find();
{ "_id" : 1, "groupid" : 2, "itemid" : 2, "settingsDoc" : [ { "level" : 10 } ] }
{ "_id" : 2, "groupid" : 3, "itemid" : 3, "settingsDoc" : [ { "level" : 30 } ] }
>
Upvotes: 1
Reputation: 22974
You can do as below using $merge
but with some more pipelines as mentioned by @D. SM
db.getCollection('test').aggregate( [
{ $match : { group: 2 } },
{ $project: {level: 1, group:1} },
{ $addFields:{item:2} },
{ $merge : { into: { db: "local", coll: "test2" }, whenMatched: [{ $addFields: {
"level":"$$new.level", "group":"$$new.group", "item":"$$new.item"
} } ] , whenNotMatched: "insert" }}
] )
Explanation:
{ $match : { group: 2 } }
Match on a field to get the document - In your case, it would be settings collection
{ $project: {level: 1, group:1} },
Project only the required fields to the next stage. You can skip this stage.
{ $addFields:{item:2} },
Using this you can add list of new fields to be inserted.
Actual magic happens in $merge
into
- db and collection where data has to be insertedwhenMatched
- add what fields to be inserted, $$new
is used to refer the fields matched in the previous stageYou can play with the pipelines to avoid unnecessary things. $merge
has more options. In this example, you can skip whenNotMatched
if you don't want to insert for non match items. You can specify to fail
in that case.
Upvotes: 1