我有一个函数可以根据给定的参数给我一些订单。
但是,参数可以为空,在那种情况下我想单独留下 $match
。
这是我目前拥有的代码:
if(req.query.status && typeof(req.query.status) == 'array'){
var match = {
$in: req.query.status
};
}else if(req.query.status){
var match = req.query.status;
}else{
//when empty find all statuses
var match = null;
}
Order.aggregate(
{
$match: {
'shop.nameSlug' : req.query.nameSlug,
}
},
{
$unwind: "$status"
},
{
$match: {
"status.status" : match
}
},
{
$group: {
_id: "$_id",
status: {
$addToSet: "$status"
},
number: {
$first: "$number"
},
date: {
$first: "$date"
},
comment: {
$first: "$comment"
}
}
}
).exec(function(err, orders){
})
当 match
为 null 时,没有订单返回,因为 mongo 正在搜索等于 null 的字段。当 match == null
时,如何删除 $match
?
最佳答案
您的意思是根据提供的选项构建整个管道。毕竟它只是一个数据结构。
您还错误地测试了“数组”,您应该使用 instanceof
因为typeof
实际上会返回 "object"
而不是 "array"
。
此外,除了在 $unwind
之后添加之外,您确实希望在 first 管道阶段中的条件也能优化选择文档。在需要的地方:
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"
}
}
]
如果您不需要过滤,则只需删除额外的管道阶段。
关于javascript - 有条件地包括聚合管道阶段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46362486/