I am trying to update a field called name
in my coll1
collection based on certain criteria. I first created a create an aggregation pipeline that filters out documents based on my criteria.
var local_filter = { "$or" :[
{'fullText': {'$eq': "404 Error"}},
{'fullText': {'$eq': "Unknown Error"}},
{'fullText': {'$eq': "503 Error"}},
{'fullText': {'$eq': "400 Error"}},
{'fullText': {'$eq': "500 Error"}},
{'fullText': {'$eq': "Read timed out"}},
{'fullText': {'$eq': "410 Error"}},
{'fullText': {'$eq': "403 Error"}},
{"fullText": {'$eq':""}},
]}
var foreign_filter= { "$and" :[
{'matchingrecords.Text': {'$ne': "404 Error"}},
{'matchingrecords.Text': {'$ne': "Unknown Error"}},
{'matchingrecords.Text': {'$ne': "503 Error"}},
{'matchingrecords.Text': {'$ne': "400 Error"}},
{'matchingrecords.Text': {'$ne': "500 Error"}},
{'matchingrecords.Text': {'$ne': "Read timed out"}},
{'matchingrecords.Text': {'$ne': "410 Error"}},
{'matchingrecords.Text': {'$ne': "403 Error"}},
{"matchingrecords.Text": {'$ne': ""}},
{"matchingrecords.Text": {'$ne':'null'}}
]}
db.coll1.aggregate([
{$match:local_filter //9474
},
{$lookup: {
from: "coll2",
localField: "_id", //from coll1
foreignField: "_id", //from coll2
as: "matchingrecords"
}//4518
},
{ $match: foreign_filter
},
{ $match: {matchingrecords: {$ne:[]} }
},//3645
{
$count: "totalCount"
}
])//3645
So, I get now 3645 documents in coll1
which I need to update the name
field. There are 2 ways I've tried, both don't work:
adding
{ $set: { "Name" :
matchingrecords.Text} }
to above pipeline. This setsName
literally with stringmatchingrecords.Text
and not the value from it. Also, adding$
doesn't help too!Using aggregation with Update, I passed my aggregation pipeline in
u
clause.
db.runCommand(
{
update: "coll1",
updates: [
{
q: { },
u: [// You can pass you aggregation pipeline here
{$match: local_filter//9474
},
{$lookup: {
from: "coll2",
localField: "_id",
foreignField: "_id",
as: "matchingrecords"
}//4518
},
{ $match: foreign_filter
},
{ $match: {matchingrecords: {$ne:[]} }
},//3645
{ $set: { "Name" : 'matchingrecords.Text' } }
],
multi: true
}
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
})
It complains that $match operator isn't allowed in update!
{
"n" : 0.0,
"nModified" : 0.0,
"writeErrors" : [
{
"index" : 0.0,
"code" : 72.0,
"errmsg" : "$match is not allowed to be used within an update"
}
],
"ok" : 1.0
}
Any suggestions on how I can update my 3645 documents?
Got a simple hack!
Solution(It worked for me!):
- Using
coll1
, create a new collection with 3645 docs.
db.coll1.aggregate([
{$match:filter //9474
},
{$lookup: {
from: "coll2",
localField: "_id",
foreignField: "_id",
as: "matchingrecords"
}//4518
},
{ $match: foreign_filter
},
{ $match: {matchingrecords: {$ne:[]} }
},//3645
{ $unwind: { path: "$matchingrecords", preserveNullAndEmptyArrays: true }
},
{ $project : <what All fields you Need?>
},
{ $out: "child_coll1"
}//get 3645 in the a new collection
- Using
coll1
, get non-matched docs in a separate collection
db.coll1.aggregate([
{$lookup: {
from: "child_coll1",
localField: "_id",
foreignField: "_id",
as: "matchingrecords"
}//
},
{ $match: {matchingrecords: {$eq:[]} }
},//30944
{ $unwind: { path: "$matchingrecords", preserveNullAndEmptyArrays: true }
},
{ $out: "child_coll2"
}//get out 30944 docs other than 3645
])
- Simply merge new collections from 1 & 2
db.child_coll1.find().forEach(function(doc){
db.child_coll2.insert(doc);
});
- delete all collection other than
child_coll2
, you can rename it tocoll1
This isn't an elegant solution, just a hack to get things done! Does anyone have a better/elegant solution in one query?