您的意思是根据提供的选项构建整个管道。毕竟它只是一个数据结构。
您还错误地测试了“数组”,您应该使用instanceof,因为typeof 实际上会返回"object" 而不是"array"。
此外,您确实希望 first 管道阶段中的条件也能以最佳方式选择文档,除了在需要的地方添加到 $unwind 之后:
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){
})
给定一个req 对象,其中包含status 中的某些内容,您会得到:
// 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"
}
}
}
]
使用数组:
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"
}
}
}
]
一无所有:
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"
}
}
}
]
因此,您可以根据提供的值查看有条件地包含部件的位置。
使用 $filter
你真的应该在这里使用$filter。它比$unwind 高效得多,而且你真的没有对任何东西进行分组。您真正想要的只是过滤数组。这就是你有条件地添加的所有内容:
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 ]
}
}
}
}}]
: []
)
];
在$in 和$eq 之间进行选择以进行比较测试,具体取决于所提供的内容。如果您“真的想”在结果中使用“集合”,则可以选择将整个内容包装在 $setUnion 中。但通常看起来您只是想从数组中“过滤”值。
对单个值的期望相同:
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"
]
}
}
}
}
}
]
一个数组:
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"
]
]
}
}
}
}
}
]
或者什么都没有:
var req = {
query: {
nameSlug: "Bill",
//status: ["A","B"]
},
};
/* 1 */
[
{
"$match" : {
"shop.nameSlug" : "Bill"
}
}
]
如果您不需要过滤,那么您只需删除额外的管道阶段。