Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb indexing embedded fields (dot notation)

Tags:

mongodb

Let's assume this is a document representing a customer.

{
    company_name: 'corporate ltd.',
    pocs: [
       {name: 'Paul', email: '[email protected]'},
       {name: 'Jessica', email: '[email protected]'}
    ]
}

I wanted to define a unique index for pocs.email So I issued the following command:

db.things.ensureIndex({"pocs.email": 1}, {unique: true})

The strange thing is that when trying to add another company with a poc having an email already exists in another company, mongo rejects that, respecting the unique index constraint.

that is, the following cannot exists:

{
    company_name: 'corporate ltd.',
    pocs: [
       {name: 'Paul', email: '[email protected]'},
       {name: 'Jessica', email: '[email protected]'}
    ]
},
{
    company_name: 'contoso llc',
    pocs: [
       {name: 'Paul', email: '[email protected]'},
    ]
}

Which is fine. However, having duplicate poc within the same doc is possible, e.g.

{
    company_name: 'corporate ltd.',
    pocs: [
       {name: 'Paul', email: '[email protected]'},
       {name: 'Paul', email: '[email protected]'},
       {name: 'Jessica', email: '[email protected]'}
    ]
},

see my cli commands sequence below:

> version()
version: 2.0.2
>
> use test
switched to db test
> db.test.ensureIndex({"poc.email": 1}, {unique: true})
> 
> db.test.insert({company: "contoso", poc: [{email: '[email protected]'}]})
> db.test.insert({company: "contoso", poc: [{email: '[email protected]'}]})
E11000 duplicate key error index: test.test.$poc.email_1  dup key: { : "[email protected]" }
> ({company: "contoso", poc: [{email: '[email protected]'}, {email: '[email protected]'}]})
> 
> 
> db.test.find()
{ "_id" : ObjectId("4f44949685926af0ecf9295d"), "company" : "contoso", "poc" : [ { "email" : "[email protected]" } ] }
{ "_id" : ObjectId("4f4494b885926af0ecf9295f"), "company" : "contoso", "poc" : [ { "email" : "[email protected]" }, { "email" : "[email protected]" } ] }

Moreover, this happens either at insert or at update.

> db.test.update({"_id" : ObjectId("4f44949685926af0ecf9295d")}, {$push: { poc: {email: '[email protected]'}}})
> db.test.find()
{ "_id" : ObjectId("4f4494b885926af0ecf9295f"), "company" : "contoso", "poc" : [ { "email" : "[email protected]" }, { "email" : "[email protected]" } ] }
{ "_id" : ObjectId("4f44949685926af0ecf9295d"), "company" : "contoso", "poc" : [        {       "email" : "[email protected]" },   {       "email" : "[email protected]" },   {       "email" : "[email protected]" } ] }
> 

Is this a bug or a by-design-feature I missed spotting in the documentation?

like image 705
Tzury Bar Yochay Avatar asked Feb 22 '12 07:02

Tzury Bar Yochay


People also ask

What is the use of the dot notation in MongoDB?

MongoDB uses the dot notation to access the elements of an array and to access the fields of an embedded document.

How do I query embedded files in MongoDB?

Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

How do you create an index on a field in MongoDB?

Indexes can be created by using the createIndex method. Indexes can be created on just one field or multiple field values. Indexes can be found by using the getIndexes method. Indexes can be removed by using the dropIndex for single indexes or dropIndexes for dropping all indexes.

Is it possible to index text with MongoDB?

MongoDB provides text indexes to support text search queries on string content. Text indexes can include any field whose value is a string or an array of string elements. A collection can only have one text search index, but that index can cover multiple fields.


1 Answers

There is an open issue regarding the same problem unique indexes not enforced within array of single document . You can vote for it.

Also there is a nice workaround suggested by Kyle Banker in this similar post Unique indexes on embedded documents

Update

This is not only related to the embedded fields, we can reproduce the same for array fields too.

>db.uniqqueTest.insert({a:[1],x:1})
>db.uniqqueTest.createIndex({a:1}, {unique: true})
> db.uniqqueTest.find()
{ "_id" : ObjectId("4f44c6252434860b44986b02"), "a" : [ 1 ],"x":1 }

and it throws an error if we try to create a new document with the same value (correct behavior )

> db.uniqqueTest.insert({a:[1],x:3})
E11000 duplicate key error index: stack.uniqqueTest.$a_1  dup key: { : 1.0 }

But this works fine if we put the same value inside the array (no errors, silently accepts the duplicate value inside the array)

> db.uniqqueTest.insert({a:[2],x:2})
> db.uniqqueTest.update({x:2},{$push:{a:2}})
{ "_id" : ObjectId("4f44c65f2434860b44986b05"), "a" : [ 2, 2 ], "x" : 2 }

But not for this

> db.uniqqueTest.update({x:2},{$push:{a:1}])
E11000 duplicate key error index: stack.uniqqueTest.$a_1  dup key: { : 1.0 }
like image 132
RameshVel Avatar answered Sep 30 '22 03:09

RameshVel