I am working with mongodb aggregate and i was able to write aggregate in mongo shell and test it and it worked fine. However when i tried to make it dynamic in Nodejs method and passed values from frontend it showed me nothing. The reason i think is with this 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. Here is my working aggregate that i wrote in 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
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
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)
. i would very much appreciate if you can tell me how can i fix this.
From the $match docs:
The $match query syntax is identical to the read operation query syntax; ie $match does not accept raw aggregation expressions. To include aggregation expression in $match, use a $expr query expression:
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:
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:
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) });
});
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.