Ali*_*nat 12 mongodb mongodb-query
我有一个包含284.116条推文的MongoDb集合.问题是某些对象中的"author"字段是对象类型,但在其他对象中 - 这个"author"字段是数组类型.所以问题是我想过滤哪些是Array,哪些是Object.
例如:作者字段的类型是对象.
{
"_id" : ObjectId("55edfbd11a87d41d987a6dc1"),
"tweet" : "Back in my dorm, yay!",
"uri" : "https://twitter.com/natalylug0/status/640994018529181696",
"date" : "2015-09-08 00:04:17",
"country" : "U.S.A.",
"city" : "Texas",
"state" : "Dallas",
"author" : {
"username" : "Nataly",
"uri" : "https://twitter.com/natalylug0",
"screenname" : "natalylug0"
}
}
Run Code Online (Sandbox Code Playgroud)
而另一个:作者字段的类型是数组.
{
"_id" : ObjectId("55ee3a00e11fbb1030d659fe"),
"author" : [
{
"username" : "Relapsed Shini",
"uri" : "https://twitter.com/iPictoraL",
"screenname" : "iPictoraL"
}
],
"tweet" : "@zumbiezuza ily zoeeeeeeee",
"uri" : "https://twitter.com/iPictoraL/status/641060812140900352",
"date" : "2015-09-08 01:29:42",
"country" : "U.S.A.",
"city" : "Texas",
"state" : "Dallas"
}
Run Code Online (Sandbox Code Playgroud)
所以我执行了这样的查询:
db.getCollection('tweets').find({ author: { $type: 4} })
Run Code Online (Sandbox Code Playgroud)
而我得到的是
Fetched 0 record(s)
Run Code Online (Sandbox Code Playgroud)
但是如果执行$ type:3,我得到284.116个值,这个值与此集合的大小相同.
所以我的问题是,如何过滤"作者"字段包含数组的对象.
Bla*_*ven 29
实际上,文档中列出了一个$type特别关于数组的"问题" :
应用于数组时,$ type匹配任何指定类型的内部元素.如果没有投影,这意味着如果任何元素具有正确的类型,整个数组将匹配.通过投影,结果将仅包括所请求类型的那些元素.
这意味着不是检测"元素本身"是否在数组中,而是实际测试的是数组的"内部元素",以查看它是什么类型.
现在,文档本身建议使用以下JavaScript测试$where:
.find({ "$where": "return Array.isArray(this.author)" })
Run Code Online (Sandbox Code Playgroud)
但我认为这是非常可怕的,因为有更好的方法.
.find({ "author.0": { "$exists": true } })
Run Code Online (Sandbox Code Playgroud)
这只是基本情况,如果存在"0th"元素,则该字段存在,因此数据是数组.
一旦你理解了这个逻辑前提,那么它就是非常简单的测试.唯一无法匹配的是"真正空"的数组,在这种情况下,如果需要,您可以回退到JavaScript替代方案.但这实际上可以使用索引,因此最好使用后一种形式.
这是做您最初要求的更好的方法。这实际上是检查某个字段是否持有数组类型值:
.find({ "author": { "$gte": [] } })
Run Code Online (Sandbox Code Playgroud)
MongoDB的数组$ type功能虽然有充分的文档证明,但IMO与所有其他$ type检查不一致,并且显然不适用于此用例,但是从2.6开始,您可以使用上述查询来检查值是否为数组(是否为空)。
我说这比当前选择的答案“更好”,因为不建议通过$ where执行代码,除非标准查询构造确实无法完成工作。
详细地说,由于缺乏执行代码中的索引的性能,因此不建议使用$ where。更多详细信息:https : //docs.mongodb.com/manual/reference/operator/query/where/#considerations
另外,如果您要专门检查非空数组,请使用以下命令:
.find({ "author": { "$gt": [] } })
Run Code Online (Sandbox Code Playgroud)
从技术上讲,此字段也比当前答案的相应$ exists解决方案好,因为该字段可能具有一个非数组对象,该对象的字段名为“ 0”,并且会匹配为“非空数组”,这是错误的在这种情况下。
从 mongoDB 版本 3.2 开始,我们有了$isArray一个聚合管道,它允许执行以下操作:
db.tweets.aggregate([
{$set: {isArray: {$cond: [{ $isArray: "$author" }, 1, 0]}}},
{$match: {isArray: 1}}
])
Run Code Online (Sandbox Code Playgroud)
甚至:
db.tweets.aggregate([
{$match: {$expr: {$isArray: "$author"}}}
])
Run Code Online (Sandbox Code Playgroud)