我想找到所有记录,其中EITHER数组中的任何项目(things1或事物2)都没有“颜色”值。 (因此,所有颜色均为”或null或不存在)
这是数据结构-
{
_id: objectId(),
things1: [
{
height:
weight:
color:
}
],
things2: [
{
size:
flavor:
color:
}
]
}
我已经尝试过了:
.find({
$and: [
{
things1:{
$elemMatch: {
$or: [
{
color: ''
},
{
color: null
},
{
color: { $exists: false }
}
]
}
}
},
{
things2:{
$elemMatch: {
$or: [
{
color: ''
},
{
color: null
},
{
color: { $exists: false }
}
]
}
}
}
]
})
这将拉回ANY记录,其中任何项目具有空白,空值或不存在的“颜色” ... 意思是如果“ things1”中有您的东西,并且三个中的两个具有颜色,而第三个是一个空字符串,并且“ things2”中的所有项目都具有颜色-上面的查询将返回此文档
我只想在其中记录所有“颜色”字段为空白,空或不存在的地方。
任何帮助表示赞赏 谢谢
答案 0 :(得分:3)
我们可以想到一条相反的路线,即必须为null,不存在或为空的字符串基本上是没有字符的字符串。我们可以计算 NOR(填充颜色存在于Things1数组中,填充颜色存在于Things2数组中。)
例如:
db.collection.find({
$nor:[
{
"things1.color":/.+/
},
{
"things2.color":/.+/
}
]
}).pretty()
答案 1 :(得分:1)
我将简化您的数据集,只是为了使示例易于读者理解,但逻辑仍然相同
{ "a" : [ { "sample" : 1 } ], "b" : [ { "sample" : 1 } ] } // No color
{ "a" : [ { "color" : "b" } ], "b" : [ { "color" : "b" } ] } // YES - Valid color
{ "b" : [ { "color" : "" }, { "color" : "a" } ] } // Empty color
{ "b" : [ { "color" : null }, { "color" : "a" } ] } // Null color
{ "b" : [ { "sample" : 1 } ] } // No color
{ "b" : [ { "color" : "b" } ] } // YES - Valid Color
{ "a" : [ { "color" : "" }, { "color" : "a" } ] } // Empty color
{ "a" : [ { "color" : null }, { "color" : "a" } ] } // Null Color
{ "a" : [ { "sample" : 1 } ] } // No color
{ "a" : [ { "color" : "b" } ] } // YES - Valid color
基本上具有您要查找的所有相同组合,因为在两个属性中,一个或两个都包含数组中的对象,而您希望该数组中的所有项都具有color
属性:< / p>
简而言之,上述文件中只有三份符合条件。所以这是获取它们的方法:
db.collection.find({
"$or": [
{
"a.color": { "$exists": true },
"a": { "$not": { "$elemMatch": { "color": { "$in": [null, ""] } } } }
},
{
"b.color": { "$exists": true },
"b": { "$not": { "$elemMatch": { "color": { "$in": [null, ""] } } } }
}
]
})
在$or
下,我们有两个成对条件。 分别(非常重要),以测试命名路径的存在,然后查找数组中任何对象与排除它们的条件(null或empty)和<使用$not
表达式来strong>拒绝这些文档。
$or
仅用于表示每个包含数组的离散字段的对。
结果当然是:
{ "a" : [ { "color" : "b" } ], "b" : [ { "color" : "b" } ] }
{ "b" : [ { "color" : "b" } ] }
{ "a" : [ { "color" : "b" } ] }
仅作为那些文档,其中所提供的外键中的一个或两个包含包含所有元素具有color
属性且值不为null
的数组。
实际上,您的意思是things1
和things2
之类的字段可以动态方式在文档之间变化,并且可能具有things3
,并且您想要所有属性及其包含数组的条件都可以匹配条件,那么对于标准查询而言,您基本上是不走运的,因此需要退回到aggregate()
。
在这里的示例中,如果我们添加了像这样的文档:
{ "a": [{ "color": "b" }, "c": [{ "color": "" }] }
然后,上面显示的基本查询表单仍将返回此文档,因此您将使用aggregate()
:
db.collection.aggregate([
{ "$addFields": {
"comb": {
"$reduce": {
"input": {
"$map": {
"input": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$in": [ "$$this.k", [ "a", "b", "c" ] ] }
}
},
"as": "el",
"in": {
"$map": {
"input": "$$el.v",
"in": {
"$mergeObjects": [
{ "type": "$$el.k" },
"$$this"
]
}
}
}
}
},
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
}
}},
{ "$match": {
"comb.color": { "$exists": true },
"comb": { "$not": { "$elemMatch": { "color": { "$in": [null, ""] } } } }
}},
{ "$addFields": {
"comb": "$$REMOVE"
}}
])
但这确实是不可取的。请注意,为了动态地遍历键,您需要$objectToArray
才能有效地将文档中的所有键本身转换为单个数组条目。然后当然使用$filter
作为 expected 键,或者替代地,将逻辑倒置为排除 _id
和其他不适用的值。
然后这会将这些数组合并,同时将key
的名称重新映射作为数组内的属性。主要注意到这里的真正要点不是"a.color"
和"b.color"
,我们现在有一个"comb"
的单个路径,表示组合映射。>
这将产生预期的结果,但是真正的解决方案应该在管道的已实现逻辑中看到,即代替带有数组的多个文档属性,更好的方法是单个数组仅使用thing1
或thing2
(或在这种情况下为"a"
或"b"
或"c"
)中的>数组。
因此,这种存储数据的方式效率更高:
{ "data" : [ { "type" : "a", "color" : "" }, { "type" : "a", "color" : "a" }, { "type" : "b", "color" : "" }, { "type" : "b", "color" : "a" } ] }
{ "data" : [ { "type" : "a", "color" : null }, { "type" : "a", "color" : "a" }, { "type" : "b", "color" : null }, { "type" : "b", "color" : "a" } ] }
{ "data" : [ { "type" : "a", "sample" : 1 }, { "type" : "b", "sample" : 1 } ] }
{ "data" : [ { "type" : "a", "color" : "b" }, { "type" : "b", "color" : "b" } ] }
{ "data" : [ { "type" : "b", "color" : "" }, { "type" : "b", "color" : "a" } ] }
{ "data" : [ { "type" : "b", "color" : null }, { "type" : "b", "color" : "a" } ] }
{ "data" : [ { "type" : "b", "sample" : 1 } ] }
{ "data" : [ { "type" : "b", "color" : "b" } ] }
{ "data" : [ { "type" : "a", "color" : "" }, { "type" : "a", "color" : "a" } ] }
{ "data" : [ { "type" : "a", "color" : null }, { "type" : "a", "color" : "a" } ] }
{ "data" : [ { "type" : "a", "sample" : 1 } ] }
{ "data" : [ { "type" : "a", "color" : "b" } ] }
{ "data" : [ { "type" : "a", "color" : "b" }, { "type" : "c", "color" : "" } ] }
如果这是您的集合结构,那么 ALL 数组元素查询将变得非常简单,基本上就是aggregate()
的最后一个阶段,该阶段实际上将您现有的结构转换为这种形式:
db.collection.find({
"data.color": { "$exists": true },
"data": { "$not": { "$elemMatch": { "color": { "$in": [null, ""] } } } }
})
然后本质上仍然符合条件的三个文档:
{ "data" : [ { "type" : "a", "color" : "b" }, { "type" : "b", "color" : "b" } ] }
{ "data" : [ { "type" : "b", "color" : "b" } ] }
{ "data" : [ { "type" : "a", "color" : "b" } ] }
在此注意,像"data.type"
这样的一致路径名具有许多优点,这也使该名称对查询选项很有用。如果只想查找等于thing1
的“类型”,就可以将其干净地添加到过滤条件中,这也使更新文档变得更加容易。
值得考虑,因为从长远来看,不依赖aggregate()
语句进行操作的基本查询表单的效果要好得多。