如何查询包含嵌套数组子集的 mongo 文档
How do I query a mongo document containing subset of nested array
这是我的文档:
var docIHave = {
_id: "someId",
things: [
{
name: "thing1",
stuff: [1,2,3,4,5,6,7,8,9]
},
{
name: "thing2",
stuff: [4,5,6,7,8,9,10,11,12,13,14]
},
{
name: "thing3",
stuff: [1,4,6,8,11,21,23,30]
}
]
}
这是我要的文档:
var docIWant = {
_id: "someId",
things: [
{
name: "thing1",
stuff: [5,6,7,8,9]
},
{
name: "thing2",
stuff: [5,6,7,8,9,10,11]
},
{
name: "thing3",
stuff: [6,8,11]
}
]
}
stuff´s of docIWant should only contain items greater than min=4
and smaller than max=12.
背景:
我有一个流星应用程序,我订阅了一个给我 docIHave 的集合。基于参数 min 和 max,我需要 docIWant "on the fly"。不得修改原始文件。我需要一个查询或过程 returns 我 docIWant 与东西的子集。
一个实用的代码示例将不胜感激。
使用 mongo aggregation 如下所示:
先在things.name
基础上使用$unwind this will unwind stuff
and then use $match to find elements greater than 4
. After that $group数据,在$project
.
中添加必填字段
查询如下:
db.collection.aggregate([
{
$unwind: "$things"
}, {
$unwind: "$things.stuff"
}, {
$match: {
"things.stuff": {
$gt: 4,
$lt:12
}
}
}, {
$group: {
"_id": "$things.name",
"stuff": {
$push: "$things.stuff"
}
}
}, {
$project: {
"thingName": "$_id",
"stuff": 1
}
}])
使用 aggregation framework for this. In the aggregation pipeline, consider the $match
运算符作为您的第一个管道阶段。这对于优化您的聚合非常必要,因为您需要先过滤符合给定条件的文档,然后再将它们传递到管道的下方。
接下来使用 $unwind
运算符。这将从输入文档中解构 things
数组字段以输出每个元素的文档。每个输出文档都是输入文档,其中数组字段的值被元素替换。
things.stuff
数组也需要另一个 $unwind
操作。
下一个流水线阶段将过滤文档,其中解构的 things.stuff
符合给定的最小和最大标准。为此使用 $match
运算符。
每组一个$group
operator is then required to group the input documents by a specified identifier expression and applies the accumulator expression $push
。这将为每个组创建一个数组表达式。
通常你的聚合应该像这样结束(虽然我没有实际测试过,但这应该让你朝着正确的方向前进):
db.collection.aggregate([
{
"$match": {
"things.stuff": { "$gt": 4, "$lte": 11 }
}
},
{
"$unwind": "$things"
},
{
"$unwind": "$things.stuff"
},
{
"$match": {
"things.stuff": { "$gt": 4, "$lte": 11 }
}
},
{
"$group": {
"_id": {
"_id": "$_id",
"things": "$things"
},
"stuff": {
"$push": "$things.stuff"
}
}
},
{
"$group": {
"_id": "$_id._id",
"things": {
"$push": {
"name": "$_id.things.name",
"stuff": "$stuff"
}
}
}
}
])
如果您需要在客户端转换文档以供显示,您可以这样做:
Template.myTemplate.helpers({
transformedDoc: function() {
// get the bounds - maybe these are stored in session vars
var min = Session.get('min');
var max = Session.get('max');
// fetch the doc somehow that needs to be transformed
var doc = SomeCollection.findOne();
// transform the thing.stuff arrays
_.each(doc.things, function(thing) {
thing.stuff = _.reject(thing.stuff, function(n) {
return (n < min) || (n > max);
});
});
// return the transformed doc
return doc;
}
});
然后在您的模板中:{{#each transformedDoc.things}}...{{/each}}
这是我的文档:
var docIHave = {
_id: "someId",
things: [
{
name: "thing1",
stuff: [1,2,3,4,5,6,7,8,9]
},
{
name: "thing2",
stuff: [4,5,6,7,8,9,10,11,12,13,14]
},
{
name: "thing3",
stuff: [1,4,6,8,11,21,23,30]
}
]
}
这是我要的文档:
var docIWant = {
_id: "someId",
things: [
{
name: "thing1",
stuff: [5,6,7,8,9]
},
{
name: "thing2",
stuff: [5,6,7,8,9,10,11]
},
{
name: "thing3",
stuff: [6,8,11]
}
]
}
stuff´s of docIWant should only contain items greater than min=4 and smaller than max=12.
背景: 我有一个流星应用程序,我订阅了一个给我 docIHave 的集合。基于参数 min 和 max,我需要 docIWant "on the fly"。不得修改原始文件。我需要一个查询或过程 returns 我 docIWant 与东西的子集。
一个实用的代码示例将不胜感激。
使用 mongo aggregation 如下所示:
先在things.name
基础上使用$unwind this will unwind stuff
and then use $match to find elements greater than 4
. After that $group数据,在$project
.
查询如下:
db.collection.aggregate([
{
$unwind: "$things"
}, {
$unwind: "$things.stuff"
}, {
$match: {
"things.stuff": {
$gt: 4,
$lt:12
}
}
}, {
$group: {
"_id": "$things.name",
"stuff": {
$push: "$things.stuff"
}
}
}, {
$project: {
"thingName": "$_id",
"stuff": 1
}
}])
使用 aggregation framework for this. In the aggregation pipeline, consider the $match
运算符作为您的第一个管道阶段。这对于优化您的聚合非常必要,因为您需要先过滤符合给定条件的文档,然后再将它们传递到管道的下方。
接下来使用 $unwind
运算符。这将从输入文档中解构 things
数组字段以输出每个元素的文档。每个输出文档都是输入文档,其中数组字段的值被元素替换。
things.stuff
数组也需要另一个 $unwind
操作。
下一个流水线阶段将过滤文档,其中解构的 things.stuff
符合给定的最小和最大标准。为此使用 $match
运算符。
每组一个$group
operator is then required to group the input documents by a specified identifier expression and applies the accumulator expression $push
。这将为每个组创建一个数组表达式。
通常你的聚合应该像这样结束(虽然我没有实际测试过,但这应该让你朝着正确的方向前进):
db.collection.aggregate([
{
"$match": {
"things.stuff": { "$gt": 4, "$lte": 11 }
}
},
{
"$unwind": "$things"
},
{
"$unwind": "$things.stuff"
},
{
"$match": {
"things.stuff": { "$gt": 4, "$lte": 11 }
}
},
{
"$group": {
"_id": {
"_id": "$_id",
"things": "$things"
},
"stuff": {
"$push": "$things.stuff"
}
}
},
{
"$group": {
"_id": "$_id._id",
"things": {
"$push": {
"name": "$_id.things.name",
"stuff": "$stuff"
}
}
}
}
])
如果您需要在客户端转换文档以供显示,您可以这样做:
Template.myTemplate.helpers({
transformedDoc: function() {
// get the bounds - maybe these are stored in session vars
var min = Session.get('min');
var max = Session.get('max');
// fetch the doc somehow that needs to be transformed
var doc = SomeCollection.findOne();
// transform the thing.stuff arrays
_.each(doc.things, function(thing) {
thing.stuff = _.reject(thing.stuff, function(n) {
return (n < min) || (n > max);
});
});
// return the transformed doc
return doc;
}
});
然后在您的模板中:{{#each transformedDoc.things}}...{{/each}}