[英]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 中的差异导致$match
、 new 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"
}
]
}
}
}
])
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.