MongoDB Object Field and Range Query Index

I have the following structure in my database:

{
    "_id" : {
       "user" : 14197,
       "date" : ISODate("2014-10-24T00:00:00.000Z")
    },
...
}

      

I have a performance issue when trying to select data by user and date range. Monogo does not use an index and does a full scan through the collection.

db.timeuse.daily.find({ "_id.user": 289006, "_id.date" : {$gt: ISODate("2014-10-23T00:00:00Z"), $lte: ISODate("2014-10-30T00:00:00Z")}}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 6,
    "nscannedObjects" : 66967,
    "nscanned" : 66967,
    "nscannedObjectsAllPlans" : 66967,
    "nscannedAllPlans" : 66967,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 523,
    "nChunkSkips" : 0,
    "millis" : 1392,
    "server" : "mongo-shard0003:27018",
    "filterSet" : false,
    "stats" : {
    "type" : "COLLSCAN",
        "works" : 66969,
        "yields" : 523,
        "unyields" : 523,
        "invalidates" : 16,
        "advanced" : 6,
        "needTime" : 66962,
        "needFetch" : 0,
        "isEOF" : 1,
        "docsTested" : 66967,
        "children" : [ ]
},
    "millis" : 1392
}

      

So far I've only found one way - use $ in.

db.timeuse.daily.find({"_id": { $in: [
    {"user": 289006, "date": ISODate("2014-10-23T00:00:00Z")},
    {"user": 289006, "date": ISODate("2014-10-24T00:00:00Z")}
]}}).explain()



{
    "cursor" : "BtreeCursor _id_",
    "isMultiKey" : false,
    "n" : 2,
    "nscannedObjects" : 2,
    "nscanned" : 2,
    "nscannedObjectsAllPlans" : 2,
    "nscannedAllPlans" : 2,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "_id" : [
            [
                {
                    "user" : 289006,
                    "date" : ISODate("2014-10-23T00:00:00Z")
                },
                {
                    "user" : 289006,
                    "date" : ISODate("2014-10-23T00:00:00Z")
                }
            ],
            [
                {
                    "user" : 289006,
                    "date" : ISODate("2014-10-24T00:00:00Z")
                },
                {
                    "user" : 289006,
                    "date" : ISODate("2014-10-24T00:00:00Z")
                }
            ]
        ]
    },

      

If there is a more elegant way to run this kind of query?

+3


source to share


1 answer


TL; The DR: do not put your data in the field _id

and use the composite index : db.timeuse.daily.ensureIndex( { "user" : 1, "date": 1 } )

.

Explanation: You are abusing key clause, _id

or more precisely, the fact that MongoDB can index entire objects. Achievement requires an index intersection or composite index , that is, either two separate indices that can be combined (this function is called > and should now be available in MongoDB, but it has limitations) or a special index on the keyset, which is called in MongoDB composite index.

Fields are _id

indexed by default, but indexed as an integer, i.e. index _id

, not just equality queries for the whole object
, not part of the object. This also explains why the request works $in

.



In general, a data structure with a default index will behave strangely. Consider this:

> db.sort.insert({"_id" : {"name" : "foo", value : 1} });
> db.sort.insert({"_id" : {"name" : "foo", value : 1, bla : "foo"} });
> db.sort.find();
{ "_id" : { "name" : "foo", "value" : 4343 } }
{ "_id" : { "name" : "foo", "value" : 4343, "bla" : "fooffo" } }

> db.sort.find({"_id" : {"name" : "foo", value : 4343} }); 
{ "_id" : { "name" : "foo", "value" : 4343 } }
// no second result here...

      

Imagine MongoDB basically hashed the entire object and just looked for the hash of the object - such an index cannot support range queries based on some part of the hash.

+1


source







All Articles