mongodb query: $size with $gt returns always 0

空扰寡人 提交于 2019-12-04 16:02:31

You cannot do that as is actually referenced in the documentation for $size. So that operator alone evaluates a "literal" result and cannot be use in conjunction with "range operators" such as you are asking.

Your only real options are to ask for a "size" that is "not equal to 0" by negating the condition with the $not operator. Which is perfectly valid:

db.userStats.count({ "sessions": { "$not": { "$size": 0 } } });

Or otherwise test with the other incarnation of $size in the aggregation framework, as long as your MongoDB version is 2.6 or greater:

db.userStats.aggregate([
    { "$group": {
         "_id": null,
         "count": {
             "$sum": {
                 "$cond": [
                     { "$gt": [ { "$size": "$sessions", 0 } ] },
                     1,
                     0
                 ]
             }
         }
    }}
])

Possibly also with the $where form of JavaScript evaluation:

db.userStats.count(function() { return this.sessions.length > 0 });

But likely slower than the last version.

Or in fact you can just do this with "dot notation", and the $exists operator:

db.userStats.count({ "sesssions.0": { "$exists": true } });

As the general idea is that if there is an element at the index 0 then the array has some length.

It all depends on your approach, but any of these forms gets the right result.

But for the "best" performance from MongoDB, don't use any of these methods. Instead, keep the array "length" as a property of the document you are inspecting. This you can "index" and the queries issued can actually access that index, which none of the above can do.

Maintain it like this:

db.userStats.update(
     { "_id": docId, "sessions": { "$ne": newItem } },
     {
         "$push": { "sessions": newItem },
         "$inc": { "countSessions": 1 }
     }
)

Or to remove:

db.userStats.update(
     { "_id": docId, "sessions": newItem  },
     {
         "$pull": { "sessions": newItem },
         "$inc": { "countSessions": -1 }
     }
)

Then you can just query on "countSesssions" which can also index for best performance:

db.userStats.find({ "countSessions": { "$gt": 0 } })

And that is the "best" way to do it.

$size does not accept a range of value. See http://docs.mongodb.org/manual/reference/operator/query/size/

To select $size for a range of value, for example from 1 to 3, you may use $or

db.userStats.count( { $or: [ {sessions:{$size:1}}, {sessions:{$size:2}}, {sessions:{$size:3}} ] } )

Certainly, $or is a working but not good solution. Do as MongoDB suggests:

To select documents based on fields with different numbers of elements, create a counter field that you increment when you add elements to a field.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!