我正在查询带有嵌套数组项的json结构。我想返回整个结构,但只包括与查询条件匹配的嵌套项。
所以 - 样本结构是
{
parentId:1,
items: [
{
field1: 1
field2: 2
},
{
field1: 3
field2: 4
}
]
}
我想查询类似的内容 - >
db.getCollection('mycollection').find({"items.field1":1, "items.field2":2})
这有效,但它也会带回第二个子项目,我希望它实际返回的是这个 - >
{
parentId:1,
items: [
{
field1: 1
field2: 2
}
]
}
我已经能够在MongoDB中创建一个查询来实现我想要的 - >
db.getCollection('mycollection').aggregate(
{ $unwind : "$items" },
{ $match : {
"items.field1": 1,
"items.field2": 2,
}}
)
但是当尝试使用mgo.v2设置它时,它证明了一点母马。 collection.Find方法似乎不喜欢$ unwind命令,似乎无法使用正确的语法来使用Pipe方法。
有没有人有任何建议如何创建?我可以创建字符串并将其传递执行吗?
答案 0 :(得分:2)
您需要的实际管道涉及使用 $filter
运算符,该运算符根据指定的条件选择要返回的数组子集。它返回一个数组,其中只包含与条件匹配的元素。
在您的情况下,您需要运行以下聚合操作
db.mycollection.aggregate([
{
"$project": {
"parentId": 1,
"items": {
"$filter": {
"input": "$items",
"as": "item",
"cond": {
"$and": [
{ "$eq": ["$$item.field1", 1] },
{ "$eq": ["$$item.field2", 2] }
]
}
}
}
}
}
])
对于不支持 $filter
运算符的MongoDB版本,您可以使用set operators的组合作为:
db.mycollection.aggregate([
{
"$project": {
"parentId": 1,
"items": {
"$setDifference": [
{ "$map": {
"input": "$items",
"as": "item",
"in": {
"$cond": [
{
"$and": [
{ "$eq": ["$$item.field1", 1] },
{ "$eq": ["$$item.field2", 2] }
]
},
"$$item",
false
]
}
}},
[false]
]
}
}
}
])
作为最后的手段,您可以使用 $unwind
运算符,因为运算符会为每个数组条目生成每个文档的副本,该副本使用更多内存(聚合管道上的可能内存上限为10)总内存百分比)因此也需要时间来产生以及处理的“时间”。您可以运行:
db.mycollection.aggregate([
{ "$unwind" : "$items" },
{ "$match" : {
"items.field1": 1,
"items.field2": 2,
}},
{
"$group": {
"_id": "$_id",
"parentId": { "$first": "$parentId" },
"items": { "$push": "$items" }
}
}
])
您可以在mgo中以pipeline:
的形式运行pipeline := []bson.M{
bson.M{ "$unwind": "$items" },
bson.M{
"$match": bson.M{
"items.field1": 1,
"items.field2": 2
}
},
bson.M{
"$group": bson.M{
"_id": "$_id",
"parentId": bson.M{ "$first": "$parentId" },
"items": bson.M{ "$push": "$items" }
}
}
}
pipe := mycollection.Pipe(pipeline)
iter := pipe.Iter()
在Robomongo进行测试
答案 1 :(得分:1)
参考chridam's answer,我相信$filter
可以简化一下:
c := session.DB("test").C("mycollection")
pipe := c.Pipe([]bson.M{{
"$project": bson.M{
"parentId": 1,
"items": bson.M{
"$filter": bson.M{
"input": "$items",
"as": "item",
"cond": bson.M{
"$and": []bson.M{
{"$eq": []interface{}{"$$item.field1", 1}},
{"$eq": []interface{}{"$$item.field2", 2}},
},
},
},
},
},
}})
resp := []bson.M{}
err = pipe.All(&resp)
if err != nil {
panic(err)
}
fmt.Println(resp)
另一个$unwind
:
c := session.DB("test").C("mycollection")
pipe := c.Pipe([]bson.M{
{"$unwind": "$items"},
{"$match": bson.M{
"items.field1": 1,
"items.field2": 2,
}},
{"$group": bson.M{
"_id": "$_id",
"parentId": bson.M{"$first": "$parentId"},
"items": bson.M{"$push": "$items"},
}},
})
resp := []bson.M{}
err = pipe.All(&resp)
if err != nil {
panic(err)
}
fmt.Println(resp)
两者都编译没有错误并返回
[map[
_id:ObjectIdHex(".....")
parentId:1
items:[map[
field2:2
field1:1
]]
]]
去1.6,mongo 3.2