如何在聚合管道mongodb中使用$ update/$ set运算符? [英] How to use $update/ $set operator in aggregation pipeline mongodb?

查看:122
本文介绍了如何在聚合管道mongodb中使用$ update/$ set运算符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据某些条件更新我的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:

  1. { $set: { "Name" : matchingrecords.Text } }添加到上述管道.这实际上将Name设置为字符串matchingrecords.Text,而不是字符串中的值.另外,添加$也无济于事!

  1. 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?

解决方案(对我有用!):

  1. 使用coll1,使用3645个文档创建一个新集合.
  1. 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

  1. 使用coll1,在单独的集合中获取不匹配的文档
  1. 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
    ])

  1. 只需合并1&中的新收藏集2

        db.child_coll1.find().forEach(function(doc){
           db.child_coll2.insert(doc); 
        });

  1. 删除除child_coll2以外的所有集合,您可以将其重命名为coll1
  1. delete all collection other than child_coll2, you can rename it to coll1

这不是一个优雅的解决方案,只是一个可以完成任务的技巧!有人在一个查询中有更好/优雅的解决方案吗?

推荐答案

为什么第一个带有聚合的解决方案不起作用?

$set不是用于聚合管道的有效阶段运算符.

$set is not a valid stage operator for aggregation pipeline.

为什么第二个带有update命令的解决方案不起作用?

Update命令不接受聚合管道运算符.从mongo@4.2开始,根据

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运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆