MongoDB - 过滤结果集中内部数组的内容

时间:2011-01-15 18:38:26

标签: filter mongodb

我是使用MongoDB的新手,我不知道如何解决下一个问题:

我有这样的文件集合:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [
         {"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}
         ]
}

首先,我想要所有包含列表中所有标签的Url。 我通过查询来解决这个问题:

db.links.find( { "Tags.Name" : { $all: ["question","answers"] } } );

但是这个查询会返回整个正确的文档,只提供正确的文档,只包含我要求的标记。

我正在寻找的结果是:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [{"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5}]
}

而不是:

{
 "URL": "www.stackoverflow.com",
 "TAGS": [{"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}]
}

因为我只要求标签[“问题”,“答案”]。

我考虑过使用MapReduce或解析结果集,但我不知道它是否是解决问题的正确方法。也许有一个内置函数可以更有效地解决它。

谢谢!

5 个答案:

答案 0 :(得分:18)

您可以使用MongoDB的聚合框架。

如果您的收藏中有一份文档,请

{
 "URL": "www.stackoverflow.com",
 "TAGS": [
         {"NAME": "question", "VOTES": 3},
         {"NAME": "answer", "VOTES": 5},
         {"NAME": "problem", "VOTES": 2}
         ]
}

并且您希望过滤数组的某些元素,您可以使用聚合样本;

db.sof_table.aggregate
([
{$unwind:'$TAGS'}, 
{$match:{'TAGS.NAME':{$in:['answer','question']}}},
{$group:{_id:'$URL',TAGS:{$push:'$TAGS'}}}
])

这将导致结果;

{
    "result" : [
        {
            "_id" : "www.stackoverflow.com",
            "TAGS" : [
                {
                    "NAME" : "question",
                    "VOTES" : 3
                },
                {
                    "NAME" : "answer",
                    "VOTES" : 5
                }
            ]
        }
    ],
    "ok" : 1
}

作为您的预期结果。

答案 1 :(得分:8)

一般来说,MongoDB上的任何find()操作都会返回与查询匹配的所有文档,并且会完整地检索所有文档。如果您只想要文档的特定部分,那么您必须在客户端进行该处理。

这是文档数据库和SQL数据库之间的根本区别。通常在文档数据库中,查询返回与其匹配的所有文档,而在SQL数据库中,您可以选择仅返回表的某些部分。当然,除非你说你做了MapReduce,但对你的用例来说这似乎有些过分。

不要阻止你使用MongoDB,但是你工作的任何项目都要考虑NoSQL数据库是否真的符合要求(它们是否满足了SQL不能满足的要求),或者你是否仍然更好地使用传统的SQL数据库。 / p>

答案 2 :(得分:3)

可以在返回的文档中禁止键和数组元素,但不能以您想要的方式。

在您的示例中,您可以使用以下查询来抑制URL密钥,该查询使用第二个参数find():

db.links.find({"TAGS.NAME" : {$all : ["question","answer"]}}, {"URL" : 0})

但是,我不相信可以使用find()基于使用$ all指定的数组成员来抑制服务器端数组的各个成员。

您可以使用$ slice仅返回数组的某些成员,但它是基于位置的。例如,

{$slice : [1, 2]}

跳过数组的第一个元素并返回到接下来的两个元素。

答案 3 :(得分:-1)

谢谢罗伯特。我已经意识到我正在寻找的功能目前还没有实现。这是issue的链接。我希望MongoDB cominuty能在短时间内实现它。谢谢!

答案 4 :(得分:-1)

这可能会对你有帮助。

  

$ elemMatch投影运算符采用显式条件参数。这允许您根据不在查询中的条件进行投影,或者是否需要基于数组嵌入文档中的多个字段进行投影。**

https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/