我有一个包含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"
}
}
另一个: 作者字段的类型是数组。
{
"_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"
}
所以我执行了这样的查询:
db.getCollection('tweets').find({ author: { $type: 4} })
我得到的是
Fetched 0 record(s)
但是如果执行 $ type:3 ,我会得到284.116个值,这个值与此集合的大小相同。
所以我的问题是,如何过滤“作者”字段包含数组的对象。
答案 0 :(得分:26)
实际上有一个"陷阱" $type
文档中列出的具体关于数组:
当应用于数组时,$ type匹配任何指定类型的内部元素。如果没有投影,这意味着如果任何元素具有正确的类型,整个数组将匹配。通过投影,结果将仅包括所请求类型的那些元素。
这意味着而不是检测"元素本身"在数组中,实际测试的是"内部元素"数组的大小,看它是什么类型。
现在,文档本身建议使用$where
进行此JavaScript测试:
.find({ "$where": "return Array.isArray(this.author)" })
但是我认为这是非常可怕的,因为有更好的方法。
诀窍在"dot notation",您要求数组的0
索引元素为$exists
.find({ "author.0": { "$exists": true } })
这只是基本情况,如果" 0th"元素存在然后该字段存在,因此数据是一个数组。
一旦你理解了这个逻辑前提,那么它就是非常简单的测试。唯一无法与之匹敌的是真正空洞的"数组,在这种情况下,如果需要,您可以回退到JavaScript替代方案。但这实际上可以使用索引,因此最好使用后一种形式。
答案 1 :(得分:4)
这是一个更好的方式来做你最初的问题;那就是实际检查某个字段是否包含数组类型值:
.find({ "author": { "$gte": [] } })
MongoDB对数组的$类型功能虽然记录良好,但是IMO与所有其他$ type检查不一致,显然不适用于这个用例,但是从2.6左右开始,你可以使用上面的查询检查值是否为数组(空或不)。
我说这是"更好"比当前选择的答案,因为不建议通过$ where执行代码,除非标准的查询结构真的无法完成工作。
详细说明,由于缺乏在执行代码中使用索引的能力而不建议使用$ where。更多细节:https://docs.mongodb.com/manual/reference/operator/query/where/#considerations
另外,如果您想特别检查非空数组,请使用:
.find({ "author": { "$gt": [] } })
从技术上讲,这个也比当前答案的相应$ exists解决方案更好,因为该字段可能有一个非数组对象,其字段名为" 0",这将匹配作为"非空数组",在这种情况下是错误的。