Những gì bạn muốn làm là xây dựng toàn bộ đường ống tùy thuộc vào các tùy chọn được cung cấp. Xét cho cùng thì nó cũng chỉ là một cấu trúc dữ liệu.
Bạn cũng đang kiểm tra không chính xác cho một "mảng" và bạn nên sử dụng instanceof
bởi vì typeof
thực sự sẽ trả về "object"
chứ không phải "array"
.
Hơn nữa, bạn thực sự muốn điều kiện đó trong lần đầu tiên giai đoạn chuyển tiếp để chọn tài liệu một cách tối ưu cũng như được thêm vào sau $unwind
khi cần thiết:
var pipeline = [
{ $match:
Object.assign(
{ 'shop.nameSlug' : req.query.nameSlug },
(req.query.status)
? { "status.status": (req.query.status instanceof Array)
? { "$in": req.query.status } : req.query.status }
: {}
)
},
{ $unwind: "$status" },
...(
(req.query.status)
? [{ "$match": {
"status.status": (req.query.status instanceof Array)
? { "$in": req.query.status } : req.query.status
}}]
: []
),
{ $group: {
_id: "$_id",
status: { $addToSet: "$status" },
number: { $first: "$number" },
date: { $first: "$date" },
comment: { $first: "$comment" }
}}
];
Order.aggregate(pipeline).exec(function(err, orders){
})
Đưa ra một req
đối tượng với một cái gì đó hiện diện ở trạng thái status
bạn nhận được:
// Example stucture
var req = {
query: {
nameSlug: "Bill",
status: "A"
},
};
// Pipeline output as:
[
{
"$match" : {
"shop.nameSlug" : "Bill",
"status.status" : "A"
}
},
{
"$unwind" : "$status"
},
{
"$match" : {
"status.status" : "A"
}
},
{
"$group" : {
"_id" : "$_id",
"status" : {
"$addToSet" : "$status"
},
"number" : {
"$first" : "$number"
},
"date" : {
"$first" : "$date"
},
"comment" : {
"$first" : "$comment"
}
}
}
]
Với một mảng:
var req = {
query: {
nameSlug: "Bill",
status: ["A","B"]
},
};
// Pipeline output as:
[
{
"$match" : {
"shop.nameSlug" : "Bill",
"status.status" : {
"$in" : [
"A",
"B"
]
}
}
},
{
"$unwind" : "$status"
},
{
"$match" : {
"status.status" : {
"$in" : [
"A",
"B"
]
}
}
},
{
"$group" : {
"_id" : "$_id",
"status" : {
"$addToSet" : "$status"
},
"number" : {
"$first" : "$number"
},
"date" : {
"$first" : "$date"
},
"comment" : {
"$first" : "$comment"
}
}
}
]
Và không có gì:
var req = {
query: {
nameSlug: "Bill",
//status: ["A","B"]
},
};
// Pipeline output as:
[
{
"$match" : {
"shop.nameSlug" : "Bill"
}
},
{
"$unwind" : "$status"
},
{
"$group" : {
"_id" : "$_id",
"status" : {
"$addToSet" : "$status"
},
"number" : {
"$first" : "$number"
},
"date" : {
"$first" : "$date"
},
"comment" : {
"$first" : "$comment"
}
}
}
]
Vì vậy, bạn có thể thấy vị trí các phần được đưa vào có điều kiện tùy thuộc vào các giá trị được cung cấp.
Sử dụng $ filter
Bạn thực sự nên sử dụng $filter
ở đây thay vào đó. Nó hiệu quả hơn nhiều so với $unwind
và bạn thực sự không nhóm bất cứ thứ gì. Tất cả những gì bạn thực sự muốn là các mảng được lọc. Vì vậy, đó là tất cả những gì bạn thêm có điều kiện:
var pipeline = [
{ $match:
Object.assign(
{ 'shop.nameSlug' : req.query.nameSlug },
(req.query.status)
? { "status.status": (req.query.status instanceof Array)
? { "$in": req.query.status } : req.query.status }
: {}
)
},
...(
(req.query.status)
? [{ "$addFields": {
"status": {
"$filter": {
"input": "$status",
"cond": {
[(req.query.status instanceof Array) ? "$in" : "$eq"]:
[ "$$this.status", req.query.status ]
}
}
}
}}]
: []
)
];
Có sự lựa chọn giữa $in
và $eq
để kiểm tra so sánh, tùy thuộc vào những gì được cung cấp. Bạn có thể tùy chọn gói toàn bộ trong $setUnion
nếu bạn "thực sự có ý" sử dụng một "tập hợp" trong kết quả. Nhưng nhìn chung, có vẻ như bạn chỉ muốn "lọc" các giá trị ra khỏi mảng.
Với cùng kỳ vọng về một giá trị duy nhất:
var req = {
query: {
nameSlug: "Bill",
//status: ["A","B"]
status: "A"
},
};
/* 1 */
[
{
"$match" : {
"shop.nameSlug" : "Bill",
"status.status" : "A"
}
},
{
"$addFields" : {
"status" : {
"$filter" : {
"input" : "$status",
"cond" : {
"$eq" : [
"$$this.status",
"A"
]
}
}
}
}
}
]
Một mảng:
var req = {
query: {
nameSlug: "Bill",
status: ["A","B"]
},
};
/* 1 */
[
{
"$match" : {
"shop.nameSlug" : "Bill",
"status.status" : {
"$in" : [
"A",
"B"
]
}
}
},
{
"$addFields" : {
"status" : {
"$filter" : {
"input" : "$status",
"cond" : {
"$in" : [
"$$this.status",
[
"A",
"B"
]
]
}
}
}
}
}
]
Hoặc không có gì:
var req = {
query: {
nameSlug: "Bill",
//status: ["A","B"]
},
};
/* 1 */
[
{
"$match" : {
"shop.nameSlug" : "Bill"
}
}
]
Nếu bạn không cần lọc, bạn chỉ cần bỏ giai đoạn đường ống bổ sung.