MongoDB投影和字段子集

MongoDB投影和字段子集,mongodb,indexing,mongodb-query,filtering,projection,Mongodb,Indexing,Mongodb Query,Filtering,Projection,我想使用mongo projections,以便向我的应用程序返回较少的数据。我想知道这是否可能 例如: user: { id: 123, some_list: [{x:1, y:2}, {x:3, y:4}], other_list: [{x:5, y:2}, {x:3, y:4}] } 给定对user\u id=123和一些“投影过滤器”的查询,如user.some\u list.x=1和user.other\u list.x=1,是否可以实现给定的结果 user: { i

我想使用mongo projections,以便向我的应用程序返回较少的数据。我想知道这是否可能

例如:

user: {
  id: 123,
  some_list: [{x:1, y:2}, {x:3, y:4}],
  other_list: [{x:5, y:2}, {x:3, y:4}]
}
给定对
user\u id=123
和一些“投影过滤器”的查询,如
user.some\u list.x=1
user.other\u list.x=1
,是否可以实现给定的结果

user: {
  id: 123,
  some_list: [{x:1, y:2}],
  other_list: []
}
其思想是让mongo多工作一点,并向应用程序检索更少的数据。在某些情况下,我们在应用程序端丢弃80%的集合元素。所以,最好不要再回来了

问题:

  • 可能吗
  • 我怎样才能做到这一点$elemMatch似乎帮不了我。我试着放松一下,但没有达到目的
  • 如果可能的话,这个投影过滤可以从
    user.x的索引中受益吗?或者,一旦用户的id已经找到,就根本不需要了
  • 谢谢。

    很可能

    使用
    findOne
    ,查询是第一个参数,投影是第二个参数。在Node/Javascript中(类似于bash):


    将返回不带
    其他\u列表
    字段的who-Will对象。或者您可以指定
    {some\u list:1}
    作为投影,返回的将只是{u id,
    some\u list

    $filter
    是您的朋友。下面生成您所寻求的输出。尝试更改
    $eq
    字段和目标值,以查看阵列中有多少项被拾取。请注意,我们是如何将新字段(一些\u列表和其他\u列表)“放在”旧字段之上的,
    $project
    基本上用过滤版本替换它们的

    db.foo.aggregate([
    {$match: {"user.id": 123}}
    ,{$project: { "user.some_list": { $filter: {
                input: "$user.some_list",
                as: "z",
                cond: {$eq: [ "$$z.x", 1 ]}
            }},
              "user.other_list": { $filter: {
        input: "$user.other_list",
                as: "z",
                cond: {$eq: [ "$$z.x", 1 ]}
                  }}
    }}
                    ]);
    

    您可以在MongoDB v3.0中执行以下操作:

    db.collection.aggregate({
        $match: {
            "user.id": 123
        }
    }, {
        $redact: {
            $cond: {
                 if: {
                     $or: [ // those are the conditions for when to include a (sub-)document
                         "$user", // if it contains a "user" field (as is the case when we're on the top level
                         "$some_list", // if it contains a "some_list" field (would be the case for the "user" sub-document)
                         "$other_list", // the same here for the "other_list" field
                         { $eq: [ "$x", 1 ] } // and lastly, when we're looking at the innermost sub-documents, we only want to include items where "x" is equal to 1
                     ] 
                 },
                 then: "$$DESCEND", // descend into sub-document
                 else: "$$PRUNE" // drop sub-document
            }
        }
    })
    
    根据您的数据设置,您还可以做些什么来简化此查询,例如:包括没有“x”字段的所有内容,或者如果存在,则需要等于1,如下所示:

    $redact: {
        $cond: {
             if: {
                 $eq: [ { "$ifNull": [ "$x", 1 ] }, 1 ] // we only want to include items where "x" is equal to 1 or where "x" does not exist
             },
             then: "$$DESCEND", // descend into sub-document
             else: "$$PRUNE" // drop sub-document
        }
    }
    
    你建议的索引对舞台没有任何作用。但是,如果您在开始时更改阶段,以删除所有无论如何都不匹配的文档,您可以从中受益,如:

    $match: {
        "user.id": 123,
        "user.some_list.x": 1 // this will use your index
    }
    

    谢谢你的回答。但是我事先不知道我想去掉其他列表中的所有元素。我想去掉所有不满足给定条件的元素。在本例中,
    other_list
    剩下0个,而
    some_list
    剩下1个。我需要检索整个
    用户
    文档,但是过滤嵌套的集合
    一些列表
    其他列表
    “$elemMatch似乎对我没有帮助”,那么您实际尝试了什么?似乎
    db.user.find({},{“某些列表”:{“$elemMatch”:{“x”:1}}},“其他列表”:{“$elemMatch”:{“x”:1}}}})
    完全按照您的要求执行。请注意,有两个不同的操作符,其中链接的操作符是“投影”操作符。使用
    .aggregate()
    ,您可以做更多有趣的事情,但简单的“单数”匹配是通过这个非常简单的案例来处理的。我在文档中发现了这一点:“$elemMatch运算符将查询结果中字段的内容限制为仅包含与$elemMatch条件匹配的第一个元素。”。在我的示例中,有一个元素加工过滤器
    用户。一些\u list.x=1
    ,但在我的实际情况中,数组中可能存在多个与过滤条件匹配的元素。在出现
    无效运算符“$filter”
    错误后,我在文档中发现了这一点:“3.2版中的新版本”。我正在使用mongo 3.0。我很抱歉不告诉你。我将尝试看看我可以使用什么,但如果可以,请提供另一个查询。谢谢,太棒了!这正是我要找的。我正在阅读文档,试图了解正在发生的事情,哈哈。一个“奇怪”的行为是,我有其他集合(
    另一个集合
    ),看起来它也被过滤了,甚至没有被列在修订中。你能想象为什么吗?但这看起来并不是问题,因为我将过滤我文档中的所有4个集合,在这个玩具示例中只使用了两个。我假设您的真实数据与您在此处发布的数据有点不同。我建议的解决方案有些不稳定,因为在不同级别的子文档中存在同名字段可能会导致一些意外行为。因此,我想,您需要对实际数据模型进行一些实验,以达到您的目标(或者升级MongoDB并使用$filter,这将是一个好主意)。听说如果它不存在可能会导致错误,但事实并非如此。我用所有4个真实的收藏品做了一些测试,效果非常好。再次感谢你。但我现在的挑战是使用groovy驱动程序语言编写它。我正在努力解决
    BasicDBObject
    和这类问题。你看到了吗:看来我在
    redact
    中得到了一些“副作用”。
    某些列表
    其他列表
    都有内部集合。在我的真实示例中,有4个集合,其中1个集合的内部集合返回的大小为0(以某种方式过滤)。为什么会这样?我想筛选
    user.some\u list.x==1
    ,如果为true则返回,但是
    user.some\u list.inner\u list
    应该保持不变。你知道为什么会发生吗?这些内部列表与外部对象(属性等)无关。他们没有属性
    x
    ,也不应该有。它们不是过滤器的主题。
    $match: {
        "user.id": 123,
        "user.some_list.x": 1 // this will use your index
    }