如何修复 $sort 不适用于 mongoDB 中数组内的数组?
How to fix $sort is not working for array inside array in mongoDB?
我的文档如下:
{
"_id" : ObjectId("622136811b68d9136e48ba4e"),
"brand_name" : "iPhone",
"brand_rating" : [
{
"cust_name" : "Sham K",
"rating" : 5
},
{
"cust_name" : "Nil",
"rating" : 5
}
],
"models" : [
{
"model_name" : "iPhone 7Plus",
"RAM" : "4GB",
"ROM" : "64GB",
"price" : 98000,
"buyer" : [
{
"cust_name" : "Anu",
"rating" : 3
},
{
"cust_name" : "Kiran",
"rating" : 4
}
]
},
{
"model_name" : "iPhone 2",
"RAM" : "3GB",
"ROM" : "32GB",
"price" : 58000,
"buyer" : [
{
"cust_name" : "Kiran",
"rating" : 4
}
]
}
]
}
问题是
按降序列出购买了 iPhone 7plus 的所有客户。
我试过了,但排序不起作用
db.brand.aggregate({$unwind : "$models"},{$match : {"models.model_name" :"iPhone 7Plus" }}, {$project : {_id : 0, "models.buyer.cust_name" : 1}}, {$sort : {"models.buyer.cust_name" : -1} })
输出:
{ "models" : { "buyer" : [ { "cust_name" : "Anu" }, { "cust_name" : "Kiran" } ] } }
> [5]
最简单的解决方法是什么?
在$sort
之前$unwind
怎么样
db.collection.aggregate({
$unwind: "$models"
},
{
$match: {
"models.model_name": "iPhone 7Plus"
}
},
{
$project: {
_id: 0,
"models.buyer.cust_name": 1
}
},
{
$unwind: "$models.buyer"
},
{
$sort: {
"models.buyer.cust_name": -1
}
})
这是一个只有 3 个阶段的变体,单个 $unwind
被尽可能“向下”推入管道,以尽量减少文档的数量和大小。此变体中的关键是使用 $filter
后跟点符号表达式来获取我们想要的数据,而不必过早使用 $unwind
。
db.foo.aggregate([
{$project: {
_id:false,
cust_name:
// Explaining this "inside out":
// 1. Start by filtering the models array for iphone 7plus.
// This will yield an array of 1 item (or zero).
// 2. We want to get the cust_name from buyer array. Use
// $map on the array of 1 to extract the names using the
// dot notation trick buyer.cust_name to create an array
// of just names.
// 3. We have that list -- but it is a list inside the array
// of one, e.g. [ [ name1, name2 ] ] . So we lift out
// the inner array with $arrayElemAt: [ inner, 0 ].
// Note: v>=4.4 you can use $first: { inner } as a convenient
// substitute for $arrayElemAt: [ inner, 0 ]
{$arrayElemAt: [
{$map: {
input: {$filter: {
input: "$models",
cond: {$eq:['$$this.model_name','iPhone 7Plus']}
}},
in: "$$this.buyer.cust_name"
}}, 0]
}
}}
// At this stage we have:
// { "cust_name" : [ "Anu", "Kiran" ] }
// Now it's easy:
,{$unwind: '$cust_name'}
,{$sort: {'cust_name':-1}}
]);
我的文档如下:
{
"_id" : ObjectId("622136811b68d9136e48ba4e"),
"brand_name" : "iPhone",
"brand_rating" : [
{
"cust_name" : "Sham K",
"rating" : 5
},
{
"cust_name" : "Nil",
"rating" : 5
}
],
"models" : [
{
"model_name" : "iPhone 7Plus",
"RAM" : "4GB",
"ROM" : "64GB",
"price" : 98000,
"buyer" : [
{
"cust_name" : "Anu",
"rating" : 3
},
{
"cust_name" : "Kiran",
"rating" : 4
}
]
},
{
"model_name" : "iPhone 2",
"RAM" : "3GB",
"ROM" : "32GB",
"price" : 58000,
"buyer" : [
{
"cust_name" : "Kiran",
"rating" : 4
}
]
}
]
}
问题是 按降序列出购买了 iPhone 7plus 的所有客户。
我试过了,但排序不起作用
db.brand.aggregate({$unwind : "$models"},{$match : {"models.model_name" :"iPhone 7Plus" }}, {$project : {_id : 0, "models.buyer.cust_name" : 1}}, {$sort : {"models.buyer.cust_name" : -1} })
输出:
{ "models" : { "buyer" : [ { "cust_name" : "Anu" }, { "cust_name" : "Kiran" } ] } }
> [5]
最简单的解决方法是什么?
在$sort
$unwind
怎么样
db.collection.aggregate({
$unwind: "$models"
},
{
$match: {
"models.model_name": "iPhone 7Plus"
}
},
{
$project: {
_id: 0,
"models.buyer.cust_name": 1
}
},
{
$unwind: "$models.buyer"
},
{
$sort: {
"models.buyer.cust_name": -1
}
})
这是一个只有 3 个阶段的变体,单个 $unwind
被尽可能“向下”推入管道,以尽量减少文档的数量和大小。此变体中的关键是使用 $filter
后跟点符号表达式来获取我们想要的数据,而不必过早使用 $unwind
。
db.foo.aggregate([
{$project: {
_id:false,
cust_name:
// Explaining this "inside out":
// 1. Start by filtering the models array for iphone 7plus.
// This will yield an array of 1 item (or zero).
// 2. We want to get the cust_name from buyer array. Use
// $map on the array of 1 to extract the names using the
// dot notation trick buyer.cust_name to create an array
// of just names.
// 3. We have that list -- but it is a list inside the array
// of one, e.g. [ [ name1, name2 ] ] . So we lift out
// the inner array with $arrayElemAt: [ inner, 0 ].
// Note: v>=4.4 you can use $first: { inner } as a convenient
// substitute for $arrayElemAt: [ inner, 0 ]
{$arrayElemAt: [
{$map: {
input: {$filter: {
input: "$models",
cond: {$eq:['$$this.model_name','iPhone 7Plus']}
}},
in: "$$this.buyer.cust_name"
}}, 0]
}
}}
// At this stage we have:
// { "cust_name" : [ "Anu", "Kiran" ] }
// Now it's easy:
,{$unwind: '$cust_name'}
,{$sort: {'cust_name':-1}}
]);