Renaud
Renaud

Reputation: 16491

mongodb index an array's key (not the values)

In MongoDB, I have the following document

{
  "_id": { "$oid" : "4FFD813FE4B0931BDAAB4F01" },
  "concepts": {
    "blabla": 20,
    "blibli": 100,
    "blublu": 250,
    ... (many more here)
  }
}

And I would like to index it to be able to query for the "key" of the "concept" array (I know it's not really a mongoDB array...):

db.things.find({concepts:blabla});

Is it possible with the above schema? Or shall I refactor my documents to something like

{
  "_id": { "$oid" : "4FFD813FE4B0931BDAAB4F01" },
  "concepts": ["blabla","blibli","blublu", ... (many more here)]
  }
}

Upvotes: 0

Views: 1296

Answers (3)

Aurélien B
Aurélien B

Reputation: 4640

You can query field presence with specific query:

db.your_collection.find({"concept.yourfield": { $exists: true }})

(notice the $exists)

It will return all your document where yourfield is a field of concept subdocument

edit: this solution is only about query. Indexes contains values not field.

Upvotes: 1

Remon van Vliet
Remon van Vliet

Reputation: 18595

I'll answer your actual question. No you cannot index on the field names given your current schema. $exists uses an index but that is an existence check only.

There are a lot of problems with a schema like the one you're using and I would suggest a refactor to :

{
  "_id": { "$oid" : "4FFD813FE4B0931BDAAB4F01" },
  "concepts": [
    {name:"blabla", value: 20},
    {name:"blibli", value: 100},
    {name:"blublu", value: 250},
    ... (many more here)
  ]
}

then index {'concepts.name:1'} and you can actually query on the concept names rather than just check for the existence.

TL;DR : No you can't.

Upvotes: 2

Erhan A
Erhan A

Reputation: 701

MongoDB indexes each value of the array so you can query for individual items.As you can find here.

But in nested arrays you need to tell to index mongodb to index your sub-fields.

  db.col1.ensureIndex({'concepts.blabla':1})
  db.col1.ensureIndex({'concepts.blublu':1})
    db.col1.find({'concepts.blabla': 20}).explain()
    {
        "cursor" : "BtreeCursor concepts.blabla_1",
        "nscanned" : 1,
        "nscannedObjects" : 1,
        "n" : 1,
        "millis" : 0,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : {
            "concepts.blabla" : [
                [
                    20,
                    20
                ]
            ]
        }
    }

After creating the index , the cursor type changes itself from BasicCursor to BtreeCursor.

if you create your document as you stated at the end of your question

{
  "_id": { "$oid" : "4FFD813FE4B0931BDAAB4F01" },
  "concepts": ["blabla","blibli","blublu", ... (many more here)]
  }
}

just the indexing will be enough as below:

db.col1.ensureIndex({'concepts':1})

Upvotes: 0

Related Questions