代码之家  ›  专栏  ›  技术社区  ›  Muirik

使用MongoDB的“$[]”操作符遍历两个数组并更新相关文档

  •  1
  • Muirik  · 技术社区  · 7 年前

    升级到Mongo 4.0后,我试图利用Mongo的新功能 $[] 功能。我基本上想做的是接收一个或多个“覆盖”ID,遍历两个数组,对传递给“覆盖”ID的匹配进行过滤更新。我的代码的相关部分如下所示:

    if (coverage) {
        let arrCoverage = [];
        arrCoverage = coverage.split(",");
    
        if (arrCoverage) {
          // convert each ID to a mongo ID
          let mongoArrCoverage = arrCoverage.map(coverage => new mongo.ObjectID(coverage));
    
          if (mongoArrCoverage) {
            try {
              let bulk = db.collection("customers").initializeUnorderedBulkOp();
              let count = 0;
              let batch = 1;
    
              db.collection("customers")
                .aggregate([
                  {
                    $match: {
                      "paymentOptions.coverages._id": {
                        $in: mongoArrCoverage
                      }
                    }
                  },
                  {
                    $unwind: "$paymentOptions"
                  },
                  {
                    $unwind: "$coverages"
                  },
                  {
                    $match: {
                      "coverages._id": {
                        $in: mongoArrCoverage
                      }
                    }
                  },
                  {
                    $project: {
                      _id: 0,
                      coverages_id: "$coverages._id",
                      "coverages.status": "$coverages.status"
                    }
                  }
                ])
                .forEach(function(doc) {
                  let coverages_id = doc.paymentOptions.coverages_id;
                  bulk
                    .find({
                      "paymentOptions.coverages._id": coverages_id
                    })
                    .updateOne({
                      $set: {
                        "paymentOptions.$[].coverages.$[].coverageEnd": lastDayOfMonth,
                        "paymentOptions.$[].coverages.$[].status": doc.paymentOptions.coverages.status == "active" ? null : doc.paymentOptions.coverages.status,
                        "paymentOptions.$[].coverages.$[].lastAdvanceDate": today
                      }
                    });
                  count++;
                  if (count == batch) {
                    bulk.execute();
                    bulk = db.collection("customers").initializeUnorderedBulkOp();
                    count = 0;
                  }
                });
    
              if (count > 0) {
                bulk.execute();
              }
    
              res.sendStatus(200);
            } catch (e) {
              console.log(e);
            }
          }
        }
      }
    };
    

    但这似乎没有达到预期的更新。我想问题可能在我做的最初汇总中?这个代码看起来正确吗?在我们之前的模型中,“coverages”数组位于文档的根上。既然它是“paymentOptions”中的一个属性,也是一个数组,我想我必须这么做 $unwind 这两个数组都在我的初始聚合中。

    顺便说一下,文件的相关部分如下所示:

    {
      _id: <ObjectId>,
      someProp: <value>,
      paymentOptions: [
        {
         _id: <ObjectId>,
         otherProp: <value>,
         coverages: [
            {
              _id: <ObjectId>,  // Want to match on this
              coverageStart: <Date>,
              coverageEnd: <Date>, // Want to update this
              status: "active"
            },
            {
              _id: <ObjectId>, // Want to match on this
              coverageStart: <Date>,
              coverageEnd: <Date>, // Want to update this
              status: "active"
            }
         ]
        }
      ]
    }
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   s7vr    7 年前

    你必须使用数组过滤器。此外,要展开嵌套数组,必须使用点符号来包含整个路径。

    像这样的东西应该管用

    if (coverage) {
      let arrCoverage = [];
      arrCoverage = coverage.split(",");
      if (arrCoverage) {
        // convert each ID to a mongo ID
        let mongoArrCoverage = arrCoverage.map(coverage => new mongo.ObjectID(coverage));
        if (mongoArrCoverage) {
          try {
            let bulk = db.collection("customers").initializeUnorderedBulkOp();
            let count = 0;
            let batch = 1;
            db.collection("customers").aggregate([{
              $match: {
                "paymentOptions.coverages._id": {
                  $in: mongoArrCoverage
                }
              }
            }, {
              $unwind: "$paymentOptions"
            }, {
              $unwind: "$paymentOptions.coverages"
            }, {
              $match: {
                "paymentOptions.coverages._id": {
                  $in: mongoArrCoverage
                }
              }
            }, {
              $project: {
                _id: 0,
                "paymentOptions_id": "$paymentOptions._id",
                "coverages_id": "$paymentOptions.coverages._id",
                "coverages_status": "$paymentOptions.coverages.status"
              }
            }]).forEach(function(doc) {
                let paymentOption_id = doc.paymentOptions_id;
                let coverages_id = doc.coverages_id;
                let status = doc.coverages_status;
                bulk.find({}).arrayFilters([
                    {"po._id": paymentOption_id},
                    {"cr._id":  coverages_id}]).updateOne({
                    $set: {
                      "paymentOptions.$[po].coverages.$[cr].coverageEnd": lastDayOfMonth,
                      "paymentOptions.$[po].coverages.$[cr].status": status == "active" ? null : status,
                      "paymentOptions.$[po].coverages.$[cr].lastAdvanceDate": today
                    }
                  }); count++;
                  if (count == batch) {
                    bulk.execute();
                    bulk = db.collection("customers").initializeUnorderedBulkOp();
                    count = 0;
                  }
                });
              if (count > 0) {
                bulk.execute();
              }
              res.sendStatus(200);
            }
            catch (e) {
              console.log(e);
            }
          }
        }
      }
    };