【问题标题】:MongoDB - Filtering the content of an internal Array in a resultsetMongoDB - 在结果集中过滤内部数组的内容
【发布时间】:2011-01-15 18:38:25
【问题描述】:

我是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}]
}

因为我只要求提供标签 ["question","answers"]。

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

谢谢!

【问题讨论】:

    标签: filter mongodb


    【解决方案1】:

    您可以使用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
    }
    

    如您所愿。

    【讨论】:

      【解决方案2】:

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

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

      并不是要阻止您使用 MongoDB,但无论您从事什么项目,都要考虑 NoSQL 数据库是否真正符合要求(它们是否满足 SQL 无法满足的要求),或者您是否仍然会更好地使用传统的 SQL 数据库。

      【讨论】:

      • 谢谢@RobV。你说的是真的,但我知道有一些方法可以只返回文档的某些键。例如:.find({},{"name":1, "age":0})。所以,我认为可能存在某种方式来过滤数组。但没问题,我会在客户端做,虽然它的性能确实很昂贵。
      • @Martin RobV 的回答是最好的。你应该给他打勾。
      【解决方案3】:

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

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

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

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

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

      {$slice : [1, 2]}
      

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

      【讨论】:

      • 谢谢罗伯特。我意识到我正在寻找的功能目前尚未实现。这是问题的链接:jira.mongodb.org/browse/SERVER-828。我希望 MongoDB 社区能在短时间内实现它。谢谢!
      【解决方案4】:

      我刚刚通过链接to my own solution to the problem 引用了此对话。它确实有效,但事后看来真正的问题是我当时不了解 MongoDB。

      我的结论:如果你发现自己在 MongoDB 中过滤嵌入式数组,那可能意味着你不了解 MongoDB。

      这个问题的官方解决方案

      official recommendation 是更喜欢嵌入数据而不是引用或过滤它。

      是的,这意味着您需要复制数据。是的,这意味着您正在使您的数据库变得不那么抽象,并且更加适合您的特定解决方案。

      是的,来自 SQL 的感觉可能很奇怪。

      意思...

      我的建议是为答案创建一个新集合,并将正确的答案嵌入到 URL 实体中。 It's called "the embedded subset pattern".

      技术上的错误解决方案

      在 MongoDB 为我点击之前,我设法过滤了服务器端的内部数组,方法是用过滤后的子集覆盖存储数组的属性。

      You can read about it here。再说一遍——尽管我真的很喜欢我的 hack,但我不推荐它。这基本上是我当时对 MongoDB 的理解程度的纪念碑。

      【讨论】:

        【解决方案5】:

        谢谢罗伯特。我意识到我正在寻找的功能目前尚未实现。这是issue 的链接。我希望 MongoDB 社区能在短时间内实现它。谢谢!

        【讨论】:

        • 注意:虽然那个jira问题已经解决了。解决方案不能解决问题。它只检索第一个匹配的子文档。 $elemMatch
        • 似乎我找到了一个过滤数组而不仅仅是返回第一个元素的解决方案。看看它是否符合您的需要:stackoverflow.com/questions/46323106/…
        【解决方案6】:

        这可能会对你有所帮助。

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

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

        【讨论】:

        • ..."只包含与 $elemMatch 条件匹配的 first 元素"
        猜你喜欢
        • 2013-01-31
        • 1970-01-01
        • 2019-07-30
        • 2012-05-17
        • 2017-01-06
        • 1970-01-01
        • 1970-01-01
        • 2021-09-18
        • 2017-11-03
        相关资源
        最近更新 更多