我正在构建一个在不同网页之间旋转的仪表板。我想要拉出所有幻灯片,这些幻灯片属于"测试"甲板并适当地订购它们。在查询之后,我的结果理想地看起来像。
[
{ "url" : "http://10.0.1.187", "position": 1, "duartion": 10 },
{ "url" : "http://10.0.1.189", "position": 2, "duartion": 3 }
]
我目前有一个类似于以下
的数据集{
"_id" : ObjectId("53a612043c24d08167b26f82"),
"url" : "http://10.0.1.189",
"decks" : [
{
"title" : "Test",
"position" : 2,
"duration" : 3
}
]
}
{
"_id" : ObjectId("53a6103e3c24d08167b26f81"),
"decks" : [
{
"title" : "Test",
"position" : 1,
"duration" : 2
},
{
"title" : "Other Deck",
"position" : 1,
"duration" : 10
}
],
"url" : "http://10.0.1.187"
}
我尝试过的查询如下:
db.slides.aggregate([
{
"$match": {
"decks.title": "Test"
}
},
{
"$sort": {
"decks.position": 1
}
},
{
"$project": {
"_id": 0,
"position": "$decks.position",
"duration": "$decks.duration",
"url": 1
}
}
]);
但它没有产生我想要的结果。如何查询我的数据集并以最佳方式获得预期结果?
答案 0 :(得分:3)
我发布后就意识到我应该使用$unwind
。此查询是最佳方式吗,还是可以不同方式完成?
db.slides.aggregate([
{
"$unwind": "$decks"
},
{
"$match": {
"decks.title": "Test"
}
},
{
"$sort": {
"decks.position": 1
}
},
{
"$project": {
"_id": 0,
"position": "$decks.position",
"duration": "$decks.duration",
"url": 1
}
}
]);
答案 1 :(得分:3)
真正的" flatten"正如你的标题所暗示的那样,$unwind
总是会被雇用,因为没有其他方法可以做到这一点。但是,如果你可以将数组过滤到匹配元素,那么有一些不同的方法。
基本上,如果你真的只有一个东西可以在数组中匹配,那么你最快的方法是简单地使用匹配所需元素的.find()
并投射:
db.slides.find(
{ "decks.title": "Test" },
{ "decks.$": 1 }
).sort({ "decks.position": 1 }).pretty()
那仍然是一个数组,但只要你只有一个匹配的元素,那么这确实有效。此外,项目按预期排序,当然"标题"字段不会从匹配的文档中删除,因为这超出了简单投影的可能性。
{
"_id" : ObjectId("53a6103e3c24d08167b26f81"),
"decks" : [
{
"title" : "Test",
"position" : 1,
"duration" : 2
}
]
}
{
"_id" : ObjectId("53a612043c24d08167b26f82"),
"decks" : [
{
"title" : "Test",
"position" : 2,
"duration" : 3
}
]
}
另一种方法,只要你有MongoDB 2.6或更高版本,就可以使用$map
运算符和其他一些运算符来同时使用"过滤"并重新塑造阵列"就地"没有实际应用$unwind
:
db.slides.aggregate([
{ "$project": {
"url": 1,
"decks": {
"$setDifference": [
{
"$map": {
"input": "$decks",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.title", "Test" ] },
{
"position": "$$el.position",
"duration": "$$el.duration"
},
false
]
}
}
},
[false]
]
}
}},
{ "$sort": { "decks.position": 1 }}
])
优点是您可以在没有"展开"的情况下进行更改,这可以减少大型数组的处理时间,因为您实际上并不是为每个数组成员创建新文档,而是运行单独的{{ 3}}阶段到"过滤"或另一个$match
来重塑。
{
"_id" : ObjectId("53a6103e3c24d08167b26f81"),
"decks" : [
{
"position" : 1,
"duration" : 2
}
],
"url" : "http://10.0.1.187"
}
{
"_id" : ObjectId("53a612043c24d08167b26f82"),
"url" : "http://10.0.1.189",
"decks" : [
{
"position" : 2,
"duration" : 3
}
]
}
您可以再次使用"过滤"数组或如果你想要你可以再次"展平"这真的是通过添加额外的$project
,您无需使用$unwind
进行过滤,因为结果中只包含匹配的项目。
但一般来说,如果你可以忍受它,那么只需使用.find()
,因为这将是最快的方式。否则你正在做的事情对于小数据是好的,或者还有其他选择可供考虑。