使用聚合在Mongodb中的复杂条件中排序 [英] Using aggregation to sorting in complex conditional in Mongodb
问题描述
我创建一个关于使用$ match的问题已经解决了,但现在我被困在一个更复杂的例子。例如,考虑我的Json的结构:
{
user:'bruno',
:[
{id:0,value:3.5},
{id:1,value:hello}
]
}
我想添加或排序,对'value'中包含的值只应用标识符'id'等于0的一些变换例如排序方法。
考虑以下数据:
db .my_collection.insert({user:'bruno',answers:[{id:0,value:3.5},{id:1,value:hello}]})
pre>
db.my_collection .insert({user:'bruno2',answers:[{id:0,value:0.5},{id:1,value:world}]})
我尝试使用:
db.my_collection.aggregate {$ sort:{answers:{$ elemMatch:{id:0,value:-1}}}})
但是,它没有工作。预期的结果是:
{user:'bruno2'answers:[{id:0,value:0.5},{id:1,value:world}]},
{user: bruno的答案:[{id:0,value:3.5},{id:1,value:hello}]})
谢谢。 >
解决方案首先,请注意,您的排序示例格式错误:聚合方法使用数组作为输入,其中数组中的每个元素都指定一个阶段在聚合管道中。另请注意, $ elemMatch 运算符不能用作$ sort阶段的一部分。
一个方法来实现你想要做的排序的例子是使用聚合框架的 $ unwind 管道操作符。展开数组会将数组元素逐个分离成单独的文档。例如,以下查询
db.my_collection.aggregate([{$ unwind:$ answers}]);
返回如下所示的内容:
[
{
_id:ObjectId(5237157f3fac8e36fdb0b96e),
user:bruno,
answers {
id:0,
value:3.5
}
},
{
_id:ObjectId(5237157f3fac8e36fdb0b96e) ,
user:bruno,
answers:{
id:1,
value:hello
} $ b},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:0,
value:0.5
}
},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:1,
value:world
}
} $ b b]
添加$ match阶段将允许您仅抓取answer.id为零的文档。最后,$ sort阶段允许你按answers.value排序。汇总查询是:
db.my_collection.aggregate([
{$ unwind:$ answers },
{$ match:{answers.id:0}},
{$ sort:{answers.value:-1}}
]
输出:
[
{
_id:ObjectId(5237157f3fac8e36fdb0b96e),
user:bruno,
answers:{
id:0,
value:3.5
}
},
{
_id:ObjectId(523715813fac8e36fdb0b96f),
user:bruno2,
answers:{
id:0,
value:0.5
}
} b $ b]
根据你的要求, $ unwind甚至聚合框架。如果相反,你想找到answer.id等于0和answers.value等于3.5的文档,然后将answers.value更改为4,你可以使用find with $ elemMatch,然后是db.collection.save():
doc = db.my_collection.findOne({answers:{$ elemMatch:{id:0,value: 3.5}}});
for(i = 0; i< doc.answers.length; i ++){
if(doc.answers [i] .id === 0){
doc.answers [i ] .value = 4;
db.my_collection.save(doc);
break;
}
}
I create a topic about using $match which was solved, but now I'm stuck in a more complex example. For example, consider the struct of my Json:
{ user: 'bruno', answers: [ {id: 0, value: 3.5}, {id: 1, value: "hello"} ] }
I would like to add or order, apply some transformations on the values contained in 'value' only the identifier 'id' equal to 0, for example a sort method.
Consider the following data:
db.my_collection.insert({ user: 'bruno', answers: [ {id: 0, value: 3.5}, {id: 1, value: "hello"}]}) db.my_collection.insert({ user: 'bruno2', answers: [ {id: 0, value: 0.5}, {id: 1, value: "world"}]})
I tried using:
db.my_collection.aggregate ({$sort: {"answers": {"$elemMatch": {id: 0, value: -1}}}})
But, it didn't work. The expected result was: {user: 'bruno2' answers: [{id: 0, value: 0.5}, {id: 1, value: "world"}]}, {user: 'bruno' answers: [{id: 0, value: 3.5}, {id: 1, value: "hello"}]})
Thank you.
解决方案First, note that your sort example is malformed: the aggregate method takes an array as input, where each element in the array specifies a stage in an aggregation pipeline. Also, note that the $elemMatch operator cannot be used as part of a $sort stage.
One way to achieve what you're trying to do with your sort example is use the aggregation framework's $unwind pipeline operator. Unwinding an array will peel the array elements off one-by-one into separate documents. For example, the following query
db.my_collection.aggregate([ {$unwind: "$answers"} ]);
returns something like the following:
[ { "_id" : ObjectId("5237157f3fac8e36fdb0b96e"), "user" : "bruno", "answers" : { "id" : 0, "value" : 3.5 } }, { "_id" : ObjectId("5237157f3fac8e36fdb0b96e"), "user" : "bruno", "answers" : { "id" : 1, "value" : "hello" } }, { "_id" : ObjectId("523715813fac8e36fdb0b96f"), "user" : "bruno2", "answers" : { "id" : 0, "value" : 0.5 } }, { "_id" : ObjectId("523715813fac8e36fdb0b96f"), "user" : "bruno2", "answers" : { "id" : 1, "value" : "world" } } ]
Adding a $match phase will allow you to grab only the documents where answers.id is zero. Finally, a $sort phase allows you to sort by answers.value. All together the aggregation query is:
db.my_collection.aggregate([ {$unwind: "$answers"}, {$match: {"answers.id": 0}}, {$sort: {"answers.value": -1}} ]);
And the output:
[ { "_id" : ObjectId("5237157f3fac8e36fdb0b96e"), "user" : "bruno", "answers" : { "id" : 0, "value" : 3.5 } }, { "_id" : ObjectId("523715813fac8e36fdb0b96f"), "user" : "bruno2", "answers" : { "id" : 0, "value" : 0.5 } } ]
Based on what your asking, it doesn't sound like you'll always need $unwind or even the aggregation framework. If instead you wanted to find the document with answers.id equal to 0 and answers.value equal to 3.5, and then change answers.value to 4 you could use find with $elemMatch followed by db.collection.save():
doc = db.my_collection.findOne({"answers": {$elemMatch: {"id": 0, "value": 3.5}}}); for (i=0; i<doc.answers.length; i++) { if (doc.answers[i].id === 0) { doc.answers[i].value = 4; db.my_collection.save(doc); break; } }
这篇关于使用聚合在Mongodb中的复杂条件中排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!