主要集合是零售商,其中包含用于商店的数组。每个商店都包含一系列优惠(您可以在此商店购买)。这提供了具有数组大小的数组。(见下面的例子)
现在我试图找到所有的优惠,这是在大小L
。
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"XS",
"S",
"M"
]
},
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"S",
"L",
"XL"
]
}
]
}
}
我尝试了这个查询:db.get集合('零售商'). fint({'stores.offers.size':'L'})
我期待这样的输出:
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size": [
"S",
"L",
"XL"
]
}
]
}
}
但是,我的查询的输出还包含与size
XS、X和M不匹配的offer。
如何强制MongoDB只返回符合我查询的报价?
问候和感谢。
它也可以在没有骨料的情况下工作。以下是解决方案链接:https://mongoplayground.net/p/Q5lxPvGK03A
db.collection.find({
"stores.offers.size": "L"
},
{
"stores": {
"$filter": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$filter": {
"input": "$$store.offers",
"as": "offer",
"cond": {
"$setIsSubset": [
[
"L"
],
"$$offer.size"
]
}
}
}
}
}
},
"as": "store",
"cond": {
"$ne": [
"$$store.offers",
[]
]
}
}
}
})
由于您的阵列已嵌入,我们无法使用$elemMatch,相反,您可以使用聚合框架获得结果:
db.retailers.aggregate([
{$match:{"stores.offers.size": 'L'}}, //just precondition can be skipped
{$unwind:"$stores"},
{$unwind:"$stores.offers"},
{$match:{"stores.offers.size": 'L'}},
{$group:{
_id:{id:"$_id", "storesId":"$stores._id"},
"offers":{$push:"$stores.offers"}
}},
{$group:{
_id:"$_id.id",
stores:{$push:{_id:"$_id.storesId","offers":"$offers"}}
}}
]).pretty()
此查询的作用是将数组展开(两次),然后匹配大小,然后将文档重塑为以前的形式。您可以删除$group步骤并查看它如何打印。玩得开心点!
因此,您的查询实际上选择了“文档”,就像它应该选择的那样。但是您要寻找的是“过滤包含的数组”,以便返回的元素只匹配查询的条件。
当然,真正的答案是,除非你真的通过过滤掉这些细节来节省大量带宽,否则你甚至不应该尝试,或者至少在第一次位置匹配之后。
MongoDB有一个位置$
操作符,它将从查询条件返回匹配索引处的数组元素。但是,这只返回最外层数组元素的“第一个”匹配索引。
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$': 1 }
)
在这种情况下,它意味着“仅存储”
数组位置。因此,如果有多个“存储”条目,则只会返回包含匹配条件的元素中的“一个”。但是,这对“offers”
的内部数组没有任何作用,因此匹配的“stores”
数组中的每个“offer”仍将返回。
MongoDB没有办法在标准查询中“过滤”这个,所以以下方法不起作用:
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$.offers.$': 1 }
)
MongoDB实际执行这种级别操作的唯一工具是聚合框架。但是分析应该告诉你为什么你“可能”不应该这样做,而只是在代码中过滤数组。
按照每个版本如何实现这一点的顺序排列。
首先使用MongoDB 3.2.x,使用$filter
操作:
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$project": {
"stores": {
"$filter": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$filter": {
"input": "$$store.offers",
"as": "offer",
"cond": {
"$setIsSubset": [ ["L"], "$$offer.size" ]
}
}
}
}
}
},
"as": "store",
"cond": { "$ne": [ "$$store.offers", [] ]}
}
}
}}
])
然后使用MongoDB 2.6.x及更高版本以及$map
和$setDifference
:
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$project": {
"stores": {
"$setDifference": [
{ "$map": {
"input": {
"$map": {
"input": "$stores",
"as": "store",
"in": {
"_id": "$$store._id",
"offers": {
"$setDifference": [
{ "$map": {
"input": "$$store.offers",
"as": "offer",
"in": {
"$cond": {
"if": { "$setIsSubset": [ ["L"], "$$offer.size" ] },
"then": "$$offer",
"else": false
}
}
}},
[false]
]
}
}
}
},
"as": "store",
"in": {
"$cond": {
"if": { "$ne": [ "$$store.offers", [] ] },
"then": "$$store",
"else": false
}
}
}},
[false]
]
}
}}
])
最后,在MongoDB 2.2.x之上引入聚合框架的任何版本中。
db.getCollection('retailers').aggregate([
{ "$match": { "stores.offers.size": "L" } },
{ "$unwind": "$stores" },
{ "$unwind": "$stores.offers" },
{ "$match": { "stores.offers.size": "L" } },
{ "$group": {
"_id": {
"_id": "$_id",
"storeId": "$stores._id",
},
"offers": { "$push": "$stores.offers" }
}},
{ "$group": {
"_id": "$_id._id",
"stores": {
"$push": {
"_id": "$_id.storeId",
"offers": "$offers"
}
}
}}
])
让我们把解释分解一下。
所以一般来说,$filter
是这里的方法,因为它是根据目的设计的。由于数组有多个级别,您需要在每个级别上应用这个。因此,首先,您将深入到商店
中的每个提供
来检查和$filter
该内容。
这里的简单比较是“大小”数组是否包含我要查找的元素”。在此逻辑上下文中,简单的操作是使用$setIsSubset
操作将[“L”]
的数组(“集合”)与目标数组进行比较。如果该条件为true
(它包含“L”),则“offers”
的数组元素将保留并在结果中返回。
在更高级别的$filter
中,您将查看前一个$filter
的结果是否为“offers”
返回空数组[]
。如果该元素不是空的,则返回该元素,否则将删除该元素。
这与现代过程非常相似,只是因为这个版本中没有$filter
,所以您可以使用$map
检查每个元素,然后使用$set差异
过滤掉返回的任何元素asfalse
.
因此$map
将返回整个数组,但是$cond
操作只是决定是返回元素还是返回一个false
值。在将$setDifference
与[false]
的单个元素“set”进行比较时,将删除返回数组中的所有false
元素。
在所有其他方面,逻辑与上述相同。
所以在MongoDB 2.6下面,处理数组的唯一工具是$unWind
,仅仅为了这个目的,你不应该为此目的使用聚合框架。
这个过程看起来确实很简单,只需简单地“拆开”每个数组,过滤掉你不需要的东西,然后把它放回原处。主要关心的是“两个”$group
阶段,“第一个”重建内部数组,下一个重建外部数组。所有级别都有不同的_id
值,因此只需要在每个级别的分组中都包含这些值。
但问题是,$unwind
的成本非常高。虽然它仍然有它的用途,但它的主要用途不是对每个文档进行这种过滤。事实上,在现代版本中,它的唯一用途应该是当数组的一个元素需要成为“分组键”本身的一部分时。
因此,在这样一个数组的多个级别上获取匹配不是一个简单的过程,事实上,如果实现不正确,那么代价会非常高昂。
只有这两个现代清单才可以用于此目的,因为除了“查询”$match
之外,它们还使用了一个“单一”管道阶段来进行“过滤”。产生的效果比标准形式的.find()
稍微多一些开销。
但是,通常情况下,这些列表仍然有一定的复杂性,除非您真的大幅减少此类过滤返回的内容,从而显著提高服务器和客户端之间使用的带宽,这样,您就可以更好地过滤初始查询和基本投影的结果。
db.getCollection('retailers').find(
{ 'stores.offers.size': 'L'},
{ 'stores.$': 1 }
).forEach(function(doc) {
// Technically this is only "one" store. So omit the projection
// if you wanted more than "one" match
doc.stores = doc.stores.filter(function(store) {
store.offers = store.offers.filter(function(offer) {
return offer.size.indexOf("L") != -1;
});
return store.offers.length != 0;
});
printjson(doc);
})
因此,使用返回的对象“发布”查询处理远没有使用聚合管道来做这件事那么迟钝。如上所述,唯一的“真正”区别是,您丢弃了“服务器”上的其他元素,而不是在收到“每个文档”时删除它们,这可能会节省一点带宽。
但是,除非您在仅使用$match
和$project
的现代版本中执行此操作,否则服务器上处理的“成本”将大大超过通过首先剥离不匹配元素来减少网络开销的“收益”。
在所有情况下,你得到相同的结果:
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"stores" : [
{
"_id" : ObjectId("56f277b5279871c20b8b4783"),
"offers" : [
{
"_id" : ObjectId("56f277b1279871c20b8b4567"),
"size" : [
"S",
"L",
"XL"
]
}
]
}
]
}
我有一个如下的猫鼬模式: 我已经获取了所有具有给定id的特定用户发表评论的帖子,即所有那些评论数组中包含uid等于给定uid的对象的文档。例如,假设用户id为101,则查询结果可能如下所示: 为了更好地理解一切,我想获取所有那些特定用户评论过的帖子,甚至回复过的帖子,以及只有该用户的评论和回复。 我所能做的就是: 此查询仅返回相应帖子的第一个匹配的评论项数组。我想要所有符合条件的物品。 请帮助我为
我是Elasticsearch的新手,我提出了一个问题,Elasticsearch嵌套查询是否只能为嵌套字段返回匹配的嵌套文档。 对于示例,我有一个名为的类型,其中嵌套字段名为 和嵌套查询 我需要的是搜索有提到足球的评论的博客文章,每个博客文章的评论数与足球相匹配(在例子中它数为1,因为另一个评论刚刚提到篮球)。 然而,Elasticsearch似乎总是返回完整的文档,所以我如何才能实现它,或者我
将mongodb与pymongo一起使用,我有以下文档: 我想更新示例子文档(这是一个数组元素,因为可能有多个示例)。我有以下代码,但它不工作... 谁能告诉我这个有什么问题吗?
我想要的是返回整个cidr数组。 我使用的是Mongo3.2和pymongo(Python3.7)
我正在查看MongoDB在和投影上的留档。我试图弄清楚如何只返回投影数组字段的子集,但我似乎无法弄清楚。 相关帖子: > 我没有试图从mongob聚合框架中执行$片-获取嵌套数组的第一个文档字段。 我也没有尝试从mongo projection中的仅返回数组值展平子文档,因为我仍然需要顶部文档中的一些字段。 假设我在集合中有以下文档: 我想要执行的查询是: 我希望它只返回数组中为的子文档下的。例如
问题内容: 我有以下查询: 这将同时返回“匹配”对象(整个文档)和“ inner_hits”对象(嵌套在匹配内部)。 有没有办法让我只返回出现在“ inner_hits”结果中的匹配“查询”元素,而没有获取整个文档? 问题答案: 应该可以通过以下方式 在顶层 禁用source- field 来实现