mongoDB通过多维数组搜索记录

mongoDB通过多维数组搜索记录,mongodb,multidimensional-array,mongodb-query,aggregation-framework,Mongodb,Multidimensional Array,Mongodb Query,Aggregation Framework,我一直在试图找出如何从mongoDB返回与另一个数组中的数组(键值对)匹配的结果。以mongo为例 { "_id" : NumberLong(19), "_t" : "OsmNode", "uname" : "Robert Whittaker", "uid" : 84263, "version" : 3, "changeset" : 1.40583e+007, "timestamp" : ISODate("2012-11-27T12:38:

我一直在试图找出如何从mongoDB返回与另一个数组中的数组(键值对)匹配的结果。以mongo为例

{
    "_id" : NumberLong(19),
    "_t" : "OsmNode",
    "uname" : "Robert Whittaker",
    "uid" : 84263,
    "version" : 3,
    "changeset" : 1.40583e+007,
    "timestamp" : ISODate("2012-11-27T12:38:46.000Z"),
    "tags" : [ 
        [ 
            "ref", 
            "SG4 90"
        ], 
        [ 
            "amenity", 
            "post_box"
        ], 
        [ 
            "box_type", 
            "lamp_box"
        ], 
        [ 
            "collection_times", 
            "Mo-Fr 16:30; Sa 09:45"
        ]
    ],
    "tagKeys" : [ 
        "ref", 
        "amenity", 
        "box_type", 
        "collection_times"
    ],
    "location" : [ 
        51.9458770751953130, 
        -0.2069800049066544
    ]
}
标记字段包含多个键值对。我想做的是返回所有包含“礼仪”键和“post_box”值的记录。做这样的事

db.getCollection('nodes').find(
    {
        "tags": [ [ 
            "amenity", 
            "post_box"
        ] ]
    }
)

不幸的是,上面只返回具有单个标记的记录,即“便利性”、“post_box”。因此,由于上面的记录包含“ref”、“box\u type”、“collection\u times”标记以及便利性标记,因此不会在查询结果中返回。环顾谷歌,我发现了许多数组示例,但没有一个数组包含另一个数组。我想我需要使用$in或£elemMatch,但尝试这些我似乎无法让他们对上述内容进行操作。

对于您当前的文档结构,您需要使用运算符

db.collection.find({'tags':{'all':[[['ament','post_box']]})
但是请注意,子数组中元素的顺序很重要,例如,下面的查询不会返回任何文档

db.collection.find({'tags':{'all':[['post_-box','ament']]})
因此,作为解决方法,您需要使用运算符

db.collection.find({
“$或”:[
{'tags':{'all':[['post_box','amentity']]},
{'tags':{'$all':[[['礼仪','邮政信箱]]}
] 
} )
因此,这里最好的做法是更改文档结构。要做到这一点,您需要使用操作来迭代和更新每个文档,以提高效率

db.collection.find().forEach(函数(doc){
var tags=doc.tags.map(函数(元素){
返回{'tagsKeys':元素[0],'value':元素[1]};
});
bulk.find({''u-id':doc.\u-id}).updateOne({
“$set”:{'tags':tags},
“$unset':{'tagKeys':'''}
}); 
计数++;
如果(计数%250==0){
//每250次操作执行一次并重新初始化
bulk.execute();
bulk=db.test.initializeOrderedBulkOp();
} 
})
//清理队列
如果(计数>0)bulk.execute()
您的文档如下所示:

{
“_id”:长(19)号,
“\u t”:“OsmNode”,
“uname”:“Robert Whittaker”,
“uid”:84263,
“版本”:3,
“变更集”:14058300,
“时间戳”:ISODate(“2012-11-27T12:38:46Z”),
“标签”:[
{
“tagsKeys”:“ref”,
“值”:“SG4 90”
},
{
“tagsKeys”:“舒适度”,
“值”:“邮政信箱”
},
{
“tagsKeys”:“盒子类型”,
“值”:“灯箱”
},
{
“tagsKeys”:“收集次数”,
“值”:“Mo Fr 16:30;Sa 09:45”
}
],
“地点”:[
51.94587707519531,
-0.2069800049066544
]
}
然后,您的查询变得更简单:

db.collection.find({'tags.tagsKeys':'ament','tags.value':'post_box'})
现在,如果“tagKey”不总是“tags”子数组中的第一个元素,那么您将需要使用提供对该元素的访问的方法

db.collection.aggregate([
{“$project”:{
“元素”:{
“$map”:{
“输入”:“$tags”,
“as”:“tag”,
“在”:{
“值”:{“$setDifference”:[“$$tag”,“$tagKeys”]},
“key”:{“$setIntersection”:[“$$tag”,“$tagKeys”]}
}
}
}
}}, 
{“$unwind”:“$element”},
{“$unwind”:“$element.key”},
{“$unwind”:“$element.value”},
{“$group”:{
“\u id”:“$\u id”,
“标签”:{
“$push”:{
“tagKey”:“$element.key”,
“值”:“$element.value”
}
}
}}
]).forEach(功能(文档){
bulk.find({'u-id':doc.\u-id}).updateOne({
“$set”:{“tags”:doc.tags},
“$unset”:{‘标记键’:”}
}); 
计数++;
如果(计数%200==0){
//每200次操作执行一次并重新初始化
bulk.execute();
bulk=db.collection.initializeOrderedBulkOp();
} 
})
//清理队列
如果(计数>0)bulk.execute()
现在我们的管道正在进行什么?

我们需要将标签的关键点与它们的价值区分开来,而我们可以做到这一点的地方就在我们的阶段。and运算符分别让我们返回出现在第一个数组中但不出现在第二个数组“tagvalue”中的元素数组和出现在所有输入集中的元素数组“tagKeys”

这里的运算符返回一个键/值对数组

由于“tagKeys”和“tagvalue”是数组,您需要解构这些数组并使用运算符。从那里,您需要保存文档,并使用累加器操作符返回新的“标记”数组,您可以使用该数组更新文档

最后但并非最不重要的一点是,您需要在文档中添加“标记键”字段,因为它不再需要。您始终可以使用以下方法检索“标记键”列表:

db.collection.distinct('tagsKeys'))

如果API及其关联方法不推荐使用,则需要使用该方法

因此,这是如何做到的:

db.collection.aggregate([
{“$project”:{
“元素”:{
“$map”:{
“输入”:“$tags”,
“as”:“tag”,
“在”:{
“值”:{“$setDifference”:[“$$tag”,“$tagKeys”]},
“key”:{“$setIntersection”:[“$$tag”,“$tagKeys”]}
}
}
}