Indexing on an object value field

In a collection all documents have a field status and its value is an object. for example: { id: 1, name: 'Draft' } or { id: 2, name: 'Published' }.
Is it okay to index status field?

Hello @Sachin_Kumar_Verma, Welcome to the MongoDB community forum,

It depends on your use case, can you share more details about what is the possible query you want to use the index?

If I am correct, consider the below document,

{ 
  "_id": "unique id",
  "status": { "id": 1, "name": "Draft" } 
}

If you create below index:

createIndex({ "status": 1 })

To use the index you have to query like this:

find({ "status": { "id": 1, "name": "Draft" } })

The below query won’t use above index,

find({ "status.id": 1, "status.name": "Draft" })

To support the index on the about query you have to create the compound index as below,

createIndex({ "status.id": 1, "status.name": 1 });
4 Likes

hi @turivishal, thanks for the reply
query on this collection will be like find({ "status": { "id": 1, "name": "Draft" } }) or find({ "status": { $ne: { "id": 1, "name": "Draft" } } }) etc.
that is why I wanted to index on status
I was just worried that indexing on an object field would not work properly since I did not find any example like that. I don’t actually understand how MongoDB does comparisons while consulting the indexes this is also part of my concern. If you know JS you know how object comparisons are based on object references instead of comparing all key-value pairs in those objects.

Hello @Sachin_Kumar_Verma,

I think the index will work perfectly, but the query will not, you have to understand the below things if you don’t know,
Consider you have documents in the collection:

[{ 
  "_id": "1",
  "status": { "id": 1, "name": "Draft" } 
},
{ 
  "_id": "2",
  "status": { "name": "Draft", "id": 1 } 
}]

Your query is:

find({ "status": { "id": 1, "name": "Draft" } })

You will get a single document, as you can see the below result:

[{ 
  "_id": "1",
  "status": { "id": 1, "name": "Draft" } 
}]

Why? Because the order of status’s value property is not equal to the original document in the collection,

{ "id": 1, "name": "Draft" }  not equal to { "name": "Draft", "id": 1 }

So you have to make sure that your insert query should always store the status’s value object in the same order.

MongoDB compares objects as values, so it is not like JS!


Out of the question:
I would suggest you experiment with these things using the MongoDB Compass, It’s easy and quick to connect your cluster, insert documents, execute queries (find, aggregate), create indexes, explain query by explain command to check does your query used index or not.

4 Likes

I think that is also true in JS.

a = { "id": 1, "name": "Draft" }
b = { "name": "Draft", "id": 1 }
a === b // evaluates to false
a == b // evaluates to false

And not store any other values in the status object.

d = { "_id" : 1 ,
    "status": { "id": 1, "name": "Draft", "_x" : 369 }
}
db.collection.insertOne( d )
db.collection.findOne( { "status": { "id": 1, "name": "Draft" } } )
/* will not find document with _id:1 because of the extra field _x */
db.collection.findOne( { "status.id": 1, "status.name": "Draft" } )
/* will find document with _id:1 despite of the extra field _x */

One feature I use, thanks to the flexible schema nature of MongoDB, is to tag or flag objects or documents with extra information to help me code and debug. I would add a field say _debug and when ever I encounter such object I print out extra information as log or trace. I would not be able to do that if using object equality rather than dot notation in my queries.

2 Likes

Just to point out, the order of key-value pairs in objects does not matter in JS for equality comparison.

a = { "id": 1, "name": "Draft" };
b = { "id": 1, "name": "Draft" };
a === b // still false
a == b // false

Object comparison is based on reference, not their actual values.

1 Like

Thanks for the clarification.