我创建一个关于使用$ 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}]}) db.my_collection .insert({user:'bruno2',answers:[{id:0,value:0.5},{id:1,value:world}]}) pre>我尝试使用:
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中的复杂条件中排序
发布评论