2

I'm trying to optimize a mongodb query. I have an index on from_account_id, to_account_id, and created_at. But the following query does a full collection scan.

{
    "ts": {
        "$date": "2012-03-18T20:29:27.038Z"
    },
    "op": "query",
    "ns": "heroku_app2281692.transactions",
    "query": {
        "$query": {
            "$or": [
                {
                    "from_account_id": {
                        "$oid": "4f55968921fcaf0001000005"
                    }
                },
                {
                    "to_account_id": {
                        "$oid": "4f55968921fcaf0001000005"
                    }
                }
            ]
        },
        "$orderby": {
            "created_at": -1
        }
    },
    "ntoreturn": 25,
    "nscanned": 2643718,
    "responseLength": 20,
    "millis": 10499,
    "client": "10.64.141.77",
    "user": "heroku_app2281692"
}

If I don't do the or, and only query from_account_id or to_account_id with an order on it, it's fast.

What's the best way to get the desired effect? Should I be keeping account_ids (both from and to) in one field like an array? Or perhaps there is a better way. Thanks!

1 Answer 1

7

Unfortunately, as you have discovered, an $or clause can make life difficult for the optimizer.

So, to work around this you have a couple options. Among them:

  • Divide your query into two and manually merge the results.
  • Change your data model to allow efficient querying. For example, you might add a "referenced_accounts" field that is an array of all the accounts referenced in the transaction.
Sign up to request clarification or add additional context in comments.

2 Comments

$or in Mongo doesn't make optimizer skip indexes. It does skip indexes for nested $or statements: jira.mongodb.org/browse/…
Btw, in case anyone was curious, I made a new Array field called referenced_accounts which auto updates using an after_update filter in rails. This single field can now be queried with an index. A little bit of duplication but it works well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.