MongoDB将数组与$ type匹配?

时间:2015-09-10 22:42:52

标签: 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"
    }
}

另一个: 作者字段的类型是数组。

{
    "_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个值,这个值与此集合的大小相同。

所以我的问题是,如何过滤“作者”字段包含数组的对象。

2 个答案:

答案 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",这将匹配作为"非空数组",在这种情况下是错误的。