MongoDB投影和字段子集
我想使用mongo projections,以便向我的应用程序返回较少的数据。我想知道这是否可能 例如: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
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%的集合元素。所以,最好不要再回来了
问题:
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
}