'How do I update a MongoDB collection with values from another collection?
I have a MongoDB collection called properties
and another collection of new data in a collection called newProperties
.
I want to update a single field (amountOwed) in properties
with the new value in newProperties
for all records where the saleNumber is the same in both tables.
I've been able to write a single update script when I hard code the values. I can't get the update script to work when using an array and then parsing it using a forEach loop. Can someone explain how to do this?
So I start with a collection called properties
that looks like this (I'm only including the relevant fields):
{
"_id" : ObjectId("551816b02eecf1238b3baadb"),
"saleNumber" : NumberInt(17917),
"saleDetails" : {
"amountOwed" : 266.0,
}
}
{
"_id" : ObjectId("551816b02eecf1238b3baadc"),
"saleNumber" : NumberInt(851400070),
"saleDetails" : {
"amountOwed" : 270.0,
}
}
I import a new collection called newProperties
that looks like this (notice the amountOwed has changed for the record with saleNumber 17917):
{
"_id" : ObjectId("551816b02eecf1238b3baadb"),
"saleNumber" : NumberInt(17917),
"saleDetails" : {
"amountOwed" : 300.0,
}
}
What I want is to update properties.saleDetails.amountOwed
with the value from newProperties.saleDetails.amountOwed
where the saleNumbers match.
Here's the query I've written:
newActiveProperties.forEach(function(doc) {
db.properties.update(
{
"saleNumber": doc.saleNumber
, "auction": ObjectId("56fbf3a8d4c6fe5d73af67c9")
},
{
$set: { "saleDetails.amountOwed": doc.saleDetails.amountOwed}
},
{
multi: true
});
});
When it runs, nothing happens. There are not results in the results tab (I'm using Mongo Chef) and none of the records get updated.
I can get it to work if I hard code the saleNumber and amountOwed:
db.properties.update(
{
"saleNumber": "17917"
, "auction": ObjectId("56fbf3a8d4c6fe5d73af67c9")
},
{
$set: { "saleDetails.amountOwed": 2000}
},
{
multi: true
});
I'm guessing it has something to do with the syntax inside a foreach loop, but I'm not sure what it is. Can someone explain how to do this?
Solution 1:[1]
With MongoDB v4.2+,
you can now use $merge
in aggregation pipeline to perform update to collections.
db.properties.aggregate([
{
"$lookup": {
"from": "newProperties",
"localField": "saleNumber",
"foreignField": "saleNumber",
"as": "newPropertiesLookup"
}
},
{
// only matched records are kept
"$unwind": "$newPropertiesLookup"
},
{
$project: {
"saleDetails.amountOwed": "$newPropertiesLookup.saleDetails.amountOwed"
}
},
{
"$merge": {
"into": "properties",
"on": "_id",
"whenMatched": "merge"
}
}
])
Here is the Mongo playground for your reference.
Prior to MongoDB v4.2,
You can use aggregation pipeline to perform the $lookup
. Then iterate the aggregation result to update the matched properties
document one-by-one.
db.properties.aggregate([
{
"$lookup": {
"from": "newProperties",
"localField": "saleNumber",
"foreignField": "saleNumber",
"as": "newPropertiesLookup"
}
},
{
// only matched records are kept
"$unwind": "$newPropertiesLookup"
}
]).forEach(function(result){
db.properties.update(
{
_id : result._id
},
{
$set: { "saleDetails.amountOwed": result.newPropertiesLookup.saleDetails.amountOwed}
}
);
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |