Reputation: 15225
I am using Mongo with Node (mongoose) and I want to know if is possible execute an update and delete in the same query.
My model is as follow:
{
_id: "1",
types: ["","", ...],
items: [{
name: "item_name",
type: "type_name"
}]
}
A real example existing now in development DB is this model:
{
"_id":"5eff1a68c75aef6db2facdf8",
"types":[
"Tier1",
"Tier2",
"TierSpecial",
"TierSuper"
],
"items":[
{
"name":"4x4 016 v1",
"type":"Tier1"
},
{
"name":"Offroad example",
"type":"Tier1"
},
{
"name":"Simulation super",
"type":"TierSuper"
},
{
"name":"Simulation Special",
"type":"TierSpecial"
}
]
}
So, I want: Update all 'type' fields in subdocuments where value is equal to a predetermined value (replace the string value). And after that delete from the array 'types'.
For example, with the real example, after execute the query and delete the type 'Tier1', result should be:
{
"_id":"5eff1a68c75aef6db2facdf8",
"types":[
"Tier2",
"TierSpecial",
"TierSuper"
],
"items":[
{
"name":"4x4 016 v1",
"type":"default"
},
{
"name":"Offroad example",
"type":"default"
},
{
"name":"Simulation super",
"type":"TierSuper"
},
{
"name":"Simulation Special",
"type":"TierSpecial"
}
]
}
Note that types
now not contais 'Tier1' and into items
, where type were 'Tier1' now is 'default'
Now I can do this work, but in two queries and I'd like to do in a single one.
These two queries are, first one to update every type
field that is equal to 'Tier1':
db.collection.update({
_id: "5eff1a68c75aef6db2facdf8",
},
{
$set: {
"items.$[elem].type": "default",
}
},
{
arrayFilters: [
{
"elem.type": "Tier1"
}
]
})
And second one to delete the value inside string array:
db.collection.update({
_id: "5eff1a68c75aef6db2facdf8",
},
{
$pull: {
types: "Tier1"
}
})
But I'd like do somthing like that:
db.collection.aggregate([
{
$facet: {
"query1": [
{
// Update query
}
],
"query2": [
{
// Delete query
}
]
}
}
])
And in this way it would be possible get information about 'query1' and 'query2'.
For example: "3 subdocuments updated and 1 type deleted"
I don't know if is possible to do that into one single query.
Thanks.
Upvotes: 0
Views: 252
Reputation: 334
//working code from Mongodb version 4.2.6 on windows 10
//regarding your first part of query you can combine both updates ($set and $pull) using aggregate a forEach.
> db.typeColl.find();
{ "_id" : 1, "types" : [ "type1" ], "items" : [ { "name" : "John", "type" : "type1" } ] }
{ "_id" : 2, "types" : [ "type2" ], "items" : [ { "name" : "Mary", "type" : "type2" } ] }
> var vtype = "type2";
> db.typeColl.aggregate([
... {$unwind:"$items"},
... {$match:{"items.type": vtype}},
... ]).forEach(function(doc){
... print("_id: ",doc._id);
... print("items type:",doc.items.type);
... //1st update
... db.typeColl.updateMany(
... {"_id":doc._id},
... {$set:{"items.$[].type":"default"}},
... {upsert:true});
... //2nd update
... db.typeColl.updateMany(
... {"_id":doc._id},
... {$pull: {types:vtype}}
... );
... }
... );
_id: 2
items type: type2
>
> db.typeColl.find();
{ "_id" : 1, "types" : [ "type1" ], "items" : [ { "name" : "John", "type" : "type1" } ] }
{ "_id" : 2, "types" : [ ], "items" : [ { "name" : "Mary", "type" : "default" } ] }
> print("MongoDB",db.version());
MongoDB 4.2.6
>
Upvotes: 1