简体   繁体   English

mongodb 聚合被字符串化并且不能在 nodejs 中工作

[英]mongodb aggregate gets stringified and does nto work in nodejs

I am working with mongodb aggregate and i was able to write aggregate in mongo shell and test it and it worked fine.我正在使用 mongodb 聚合,我能够在 mongo shell 中编写聚合并对其进行测试,它运行良好。 However when i tried to make it dynamic in Nodejs method and passed values from frontend it showed me nothing.但是,当我尝试在 Nodejs 方法中使其动态化并从前端传递值时,它什么也没显示。 The reason i think is with this new ObjectId(YOUR ID IN STRING TYPE) .我认为的原因是这个new ObjectId(YOUR ID IN STRING TYPE) The moment i pass the aggregate to execute function it gets strigified and new ObjectId gets removed so then it does not get matched.在我通过聚合执行 function 的那一刻,它会被触发并且new ObjectId会被删除,因此它不会被匹配。 Here is my working aggregate that i wrote in mongo shell这是我在 mongo shell 中编写的工作汇总

db.ParcelStatus.aggregate([
  {
    $match: {
      $or: [
        {
          "statusRepositoryId": new ObjectId("5dd7fa20dcfa9600152cc2d8")
        },
        {
          "statusRepositoryId": new ObjectId("5dd7fa20dcfa9600152cc2dd")
        },
        {
          "createdAt": {
            "$gte": new Date("2020-05-01T18:59:59.001Z")
          }
        },
        {
          "createdAt": {
            "$lte": new Date("2020-05-31T18:59:59.099Z")
          }
        }
      ]
    }
  },
  {
    "$lookup": {
      "from": "Parcel",
      "localField": "parcelId",
      "foreignField": "_id",
      "as": "parcel"
    }
  },
  {
    "$unwind": {
      "path": "$parcel",
      "preserveNullAndEmptyArrays": true
    }
  },
  {
    "$lookup": {
      "from": "CustomerData",
      "localField": "parcel.customerDataId",
      "foreignField": "_id",
      "as": "parcel.customerData"
    }
  },
  {
    "$unwind": "$parcel.customerData"
  },
  {
    "$lookup": {
      "from": "Customer",
      "localField": "parcel.customerData.customerId",
      "foreignField": "_id",
      "as": "parcel.customerData.customer"
    }
  },
  {
    "$unwind": "$parcel.customerData.customer"
  },
  {
    "$lookup": {
      "from": "City",
      "localField": "parcel.customerData.cityId",
      "foreignField": "_id",
      "as": "parcel.customerData.city"
    }
  },
  {
    "$unwind": "$parcel.customerData.city"
  }
])

Now in nodejs here is how i am building it现在在 nodejs 中,这是我构建它的方式

 let pipeline = [];
  const matchObj = {
    $match: { $or: [] },
  };
  filters.forEach((obj) => {
    if (obj.key === "date") {
      matchObj.$match.$or.push(
        { createdAt: { $gte: new Date(obj.values.from) } },
        { createdAt: { $lte: new Date(obj.values.to) } }
      );
    }
    if (obj.key === "status_repository") {
      if (
        report.filters.find((x) => x.key === obj.key).selectionType === "single"
      ) {
        matchObj.$match.$or.push({
          statusRepositoryId: { $toObjectId: obj.values },
        });
      } else {
        obj.values.forEach((id) => {
          matchObj.$match.$or.push({ statusRepositoryId: { $toObjectId: id } });
        });
      }
    }
  });

  pipeline.push(matchObj);

  pipeline = [
    ...pipeline,
    {
      $lookup: {
        from: "Parcel",
        localField: "parcelId",
        foreignField: "_id",
        as: "parcel",
      },
    },
    {
      $unwind: {
        path: "$parcel",
        preserveNullAndEmptyArrays: true,
      },
    },
    {
      $lookup: {
        from: "CustomerData",
        localField: "parcel.customerDataId",
        foreignField: "_id",
        as: "parcel.customerData",
      },
    },
    { $unwind: "$parcel.customerData" },
    {
      $lookup: {
        from: "Customer",
        localField: "parcel.customerData.customerId",
        foreignField: "_id",
        as: "parcel.customerData.customer",
      },
    },
    { $unwind: "$parcel.customerData.customer" },
    {
      $lookup: {
        from: "City",
        localField: "parcel.customerData.cityId",
        foreignField: "_id",
        as: "parcel.customerData.city",
      },
    },
    {
      $unwind: "$parcel.customerData.city",
    },
  ];

and in nodejs this is how it shows up in console在nodejs中,这就是它在控制台中的显示方式

db.ParcelStatus.aggregate([
  {
    "$match": {
      "$or": [
        {
          "statusRepositoryId": "5dd7fa20dcfa9600152cc2d8"
        },
        {
          "statusRepositoryId":"5dd7fa20dcfa9600152cc2dd"
        },
        {
          "createdAt": {
            "$gte": "2020-05-01T18:59:59.001Z"
          }
        },
        {
          "createdAt": {
            "$lte": "2020-05-31T18:59:59.099Z"
          }
        }
      ]
    }
  },
  {
    "$lookup": {
      "from": "Parcel",
      "localField": "parcelId",
      "foreignField": "_id",
      "as": "parcel"
    }
  },
  {
    "$unwind": {
      "path": "$parcel",
      "preserveNullAndEmptyArrays": true
    }
  },
  {
    "$lookup": {
      "from": "CustomerData",
      "localField": "parcel.customerDataId",
      "foreignField": "_id",
      "as": "parcel.customerData"
    }
  },
  {
    "$unwind": "$parcel.customerData"
  },
  {
    "$lookup": {
      "from": "Customer",
      "localField": "parcel.customerData.customerId",
      "foreignField": "_id",
      "as": "parcel.customerData.customer"
    }
  },
  {
    "$unwind": "$parcel.customerData.customer"
  },
  {
    "$lookup": {
      "from": "City",
      "localField": "parcel.customerData.cityId",
      "foreignField": "_id",
      "as": "parcel.customerData.city"
    }
  },
  {
    "$unwind": "$parcel.customerData.city"
  }
])

Notice the difference in nodejs result in $match , new Date(DATE) and in new ObjectId(ID) .请注意 nodejs 中的差异导致$matchnew Date(DATE)new ObjectId(ID) i would very much appreciate if you can tell me how can i fix this.如果您能告诉我如何解决此问题,我将不胜感激。

From the $match docs:来自$match文档:

The $match query syntax is identical to the read operation query syntax; $match 查询语法与读操作查询语法相同; ie $match does not accept raw aggregation expressions.即 $match 不接受原始聚合表达式。 To include aggregation expression in $match, use a $expr query expression:要在 $match 中包含聚合表达式,请使用 $expr 查询表达式:

What are raw aggregation expressions ?什么是原始聚合表达式

Expressions can include field paths, literals, system variables, expression objects, and expression operators.表达式可以包括字段路径、文字、系统变量、表达式对象和表达式运算符。 Expressions can be nested.表达式可以嵌套。

And in our context $toObjectId is an aggregation expression operators which means we cannot use it in $match without using $expr , like so:在我们的上下文中$toObjectId是一个聚合表达式运算符,这意味着我们不能在$match使用它而不使用$expr ,如下所示:

db.collection.aggregate([
  {
    $match: {
      $expr: {
        $eq: [
          "$statusRepositoryId",
          {
            $toObjectId: "5dd7fa20dcfa9600152cc2d8"
          }
        ]
      }
    }
  }
])

Mongo Playground蒙戈游乐场

Meaning you'll have to re-structure your query which could be quite annoying.这意味着您将不得不重新构建您的查询,这可能会很烦人。 But we do have a better solution, just import ObjectId from Mongo and cast the string to that while constructing the query:但我们确实有更好的解决方案,只需从 Mongo 导入ObjectId并在构造查询时将字符串转换为该字符串:

 if (obj.key === "status_repository") {
      if (
        report.filters.find((x) => x.key === obj.key).selectionType === "single"
      ) {
        matchObj.$match.$or.push({
          statusRepositoryId: new ObjectId(obj.values),
        });
      } else {
        obj.values.forEach((id) => {
          matchObj.$match.$or.push({ statusRepositoryId:  new ObjectId(id) });
        });
      }
    }

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

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