简体   繁体   English

基于匹配的查询MongoDB NodeJS更新所有文档和嵌入文档中的字段

[英]Update a field in all documents and embedded documents based on matching query MongoDB NodeJS

I have pretty complex query that I am trying to write and can't seem to wrap my head around the best way to write it. 我有一个非常复杂的查询,我正在尝试编写,似乎无法围绕编写它的最佳方式。 Ultimately I am trying to avoid having to write it all out manually. 最终,我试图避免手动全部写出来。 What I am trying to do is to take a dynamic field and go through each document to see if that field exists and if it does then update it. 我想要做的是获取一个动态字段并浏览每个文档以查看该字段是否存在以及是否存在然后更新它。 The issue is that the field can exist more than once in document since it can exist on an embedded level in multiple embedded documents per single parent document. 问题是该字段可以在文档中存在多次,因为它可以存在于每个单个父文档的多个嵌入文档中的嵌入级别上。

Here is what a typical object would look like: 以下是典型对象的外观:

applications: {
   _id: 5368hss76sd9f,
   ProgramAreaId: 1,
   ProgramArea: 'Education',
   StrategyId: 16,
   Strategy: 'Graduate Program',
   AlternateMapping: [{
         ProgramAreaId: 2,
         ProgramArea: 'Private Sector',
         StrategyId: 13,
         Strategy: 'Higher Education Fund'
   }],
   Funding: [{
         Amount: '500000'
         StrategyId: 16
         Strategy: 'Graduate Program'
      },
      {
         Amount: '500000'
         StrategyId: 13
         Strategy: 'Higher Education Fund'
      }
   ]
}

I may have several thousand of these that I will need to update at a time. 我可能有几千个这样的,我需要一次更新。 The ultimate goal would be to do it in one query. 最终目标是在一个查询中完成。 I have made it work for a single field at the base level but was wondering if there was a way to make it work for all of the fields that match the dynamic name even in embedded documents. 我已经使它适用于基础级别的单个字段,但是想知道是否有一种方法可以使其适用于所有与动态名称匹配的字段,即使在嵌入式文档中也是如此。

Here is what I have tried so far: 这是我到目前为止所尝试的:

     var fieldId = obj.Type + 'Id'; //obj.Type could equal 'Strategy' or 'ProgramArea'
     var field = obj.Type;
     var id = 13; //This could be any number of ids and ultimately was what I want to match on.
        var qry = {
            $where: function() {
                var deepIterate = function(o, value) {
                    for (var field in o) {
                        if (field == fieldId && obj[field] == value) {
                            console.log()
                            return true;
                        }
                        var found = false;
                        if (typeof o[field] === 'object') {
                            found = deepIterate(o[field], value)
                            if (found) {
                                return true;
                            }
                        }
                    }
                    return false;
                };
                return deepIterate(this, id)
            }
        };

        var setQry = { $set: {} };
        setQry.$set[field] = obj.Name;//Field here would be 'Strategy' or 'ProgramArea' or any number of other fields I could be updateing and Name is what I want the value of that field to equal.

        mongo.collection('applications').updateMany(qry, setQry, function(err, result) {
            if (err)
                callback(null);
            else
                callback(result);
        });

The above query will find me any 'application' that contains the field name equal to the field name I am asking for and it will even search through embedded documents to see if that field is there. 上面的查询将找到任何包含字段名称等于我要求的字段名称的“应用程序”,它甚至会搜索嵌入的文档以查看该字段是否存在。 The issue with the above query is that it will only update that field on the parent level rather than updating the children as well. 上述查询的问题是它只会在父级别更新该字段,而不是更新子级。

So I think I have found the best solution to the above code. 所以我认为我找到了上述代码的最佳解决方案。 I created this following code to accomplish the above issue and it works wonderfully! 我创建了以下代码来完成上述问题,它运行得非常好!

   var resultsArray = [];
var fieldId = obj.Type + 'Id';
var field = obj.Type;
if (coll == 'statuses') {
    fieldId = "StatusId";
    field = "Status";
}

var altmapField = 'AltMaps.' + fieldId,
    altfundField = 'AltFunds.' + fieldId,
    paymentField = 'Payments.' + fieldId,
    reportField = 'Reports.' + fieldId,
    crosswalkField = 'Crosswalk.' + fieldId,
    regionField = 'RegionBreakdowns.' + fieldId,
    sectorField = 'SectorBreakdowns.' + fieldId;
var qry = [];
qry.push({
    $match: {
        $or: [{
        }, {
        }, {
        }, {
        }, {
        }, {
        }, {
        }, {
        }]
    }
});

qry[0].$match.$or[0][fieldId] = id;
qry[0].$match.$or[1][altmapField] = id;
qry[0].$match.$or[2][altfundField] = id;
qry[0].$match.$or[3][paymentField] = id;
qry[0].$match.$or[4][reportField] = id;
qry[0].$match.$or[5][crosswalkField] = id;
qry[0].$match.$or[6][regionField] = id;
qry[0].$match.$or[7][sectorField] = id;


var cursor = mongo.collection(collectionPrefix + 'applications').aggregate(qry, { allowDiskUse: true, explain: false }, null);

Essentially all I did was build out a query dynamically and then pass that into mongo aggregation and it read it like a champ. 基本上我所做的只是动态构建一个查询,然后将其传递给mongo聚合,它就像一个冠军一样读取它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM