我正在尝试根据某些条件更新我的coll1集合中名为name的字段.我首先创建了一个创建聚合管道,该管道根据我的标准过滤掉文档.
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因此,我现在在coll1中得到3645个文档,我需要更新name字段.我尝试了2种方法,但两种方法都不起作用:
So, I get now 3645 documents in coll1which I need to update the name field. There are 2 ways I've tried, both don't work:
将{ $set: { "Name" : matchingrecords.Text } }添加到上述管道.这实际上将Name设置为字符串matchingrecords.Text,而不是字符串中的值.另外,添加$也无济于事!
adding { $set: { "Name" :matchingrecords.Text} } to above pipeline. This sets Name literally with string matchingrecords.Text and not the value from it. Also, adding $ doesn't help too!
使用通过Update进行聚合,我在u子句中通过了聚合管道.
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 } })
它抱怨$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 }关于如何更新3645文档的任何建议?
Any suggestions on how I can update my 3645 documents?
解决方案(对我有用!):
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
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 ])
db.child_coll1.find().forEach(function(doc){ db.child_coll2.insert(doc); });
这不是一个优雅的解决方案,只是一个可以完成任务的技巧!有人在一个查询中有更好/优雅的解决方案吗?
推荐答案为什么第一个带有聚合的解决方案不起作用?
$set不是用于聚合管道的有效阶段运算符.
$set is not a valid stage operator for aggregation pipeline.
为什么第二个带有update命令的解决方案不起作用?
Update命令不接受聚合管道运算符.从mongo@4.2开始,根据参考由@prasad _
Update command does not accept aggregation pipeline operators. Only couple of operators are supported starting mongo@4.2 as per reference shared by @prasad_
那么如何解决此问题?
检查是否可以将$replaceRoot用于您的用例.如果没有,您可以使用以下技巧.
Check if you can use $replaceRoot for your use case or not. If not, you can use following hack.
首先像您一样首先进行聚合,然后添加$addFields阶段,为每个文档添加一个具有您要设置的值的新字段.然后按如下所示运行另一个更新命令
First start with aggregation as you did first and add $addFields stage to add a new field for each document with the value you want to set. Then run another update command as following
db.coll1.aggregate([ { // your match queries }, { $addField: { myNewName: "myvalue" } } ]).toArray().forEach(function(myDoc){ db.coll1.update({ _id: myDoc.id }, { $set: {Name: myDoc.myNewName } }) })更多推荐
如何在聚合管道mongodb中使用$ update/$ set运算符?
发布评论