MongoDB: Unique index on array element's property
I have a structure similar to this:
class Cat {
int id;
List<Kitten> kittens;
}
class Kitten {
int id;
}
I'd like to prevent users from creating a cat with more than one kitten with the same id. I've tried creating an index as follows:
db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})
But when I attempt to insert a badly-formatted cat, Mongo accepts it.
Am I missing something? can this even be done?
mongodb
add a comment |
I have a structure similar to this:
class Cat {
int id;
List<Kitten> kittens;
}
class Kitten {
int id;
}
I'd like to prevent users from creating a cat with more than one kitten with the same id. I've tried creating an index as follows:
db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})
But when I attempt to insert a badly-formatted cat, Mongo accepts it.
Am I missing something? can this even be done?
mongodb
1
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19
add a comment |
I have a structure similar to this:
class Cat {
int id;
List<Kitten> kittens;
}
class Kitten {
int id;
}
I'd like to prevent users from creating a cat with more than one kitten with the same id. I've tried creating an index as follows:
db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})
But when I attempt to insert a badly-formatted cat, Mongo accepts it.
Am I missing something? can this even be done?
mongodb
I have a structure similar to this:
class Cat {
int id;
List<Kitten> kittens;
}
class Kitten {
int id;
}
I'd like to prevent users from creating a cat with more than one kitten with the same id. I've tried creating an index as follows:
db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})
But when I attempt to insert a badly-formatted cat, Mongo accepts it.
Am I missing something? can this even be done?
mongodb
mongodb
asked Jul 19 '11 at 7:48
Electric MonkElectric Monk
1,33511633
1,33511633
1
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19
add a comment |
1
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19
1
1
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19
add a comment |
4 Answers
4
active
oldest
votes
As far as I know, unique indexes only enforce uniqueness across different documents, so this would throw a duplicate key error:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
But this is allowed:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
I'm not sure if there's any way enforce the constraint you need at the Mongo level, maybe it's something you could check in the application logic when you insert of update?
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
add a comment |
Ensuring uniqueness of the individual values in an array field
In addition to the example above, there is a function in MongoDB to ensure that when you are adding a new object/value to an array field, that it will only perform the update if the value/object doesn't already exist.
So if you have a document that looks like this:
{ _id: 123, kittens: [456] }
This would be allowed:
db.cats.update({_id:123}, {$push: {kittens:456}})
resulting in
{ _id: 123, kittens: [456, 456] }
however using the $addToSet function (as opposed to $push) would check if the value already exists before adding it.
So, starting with:
{ _id: 123, kittens: [456] }
then executing:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Would not have any effect.
So, long story short, unique constraints don't validate uniqueness within the value items of an array field, just that two documents can't have identical values in the indexed fields.
add a comment |
There is an equivalent of insert with uniquness in array attribute. The following command essentially does insert while ensuring the uniqueness of kittens (upsert creates it for you if the object with 123 doesn't already exist).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
The resulting value of the object will be
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}
The important properties are:$addToSet
andupsert
. The$set
property is unrelated to the OP.
– Michael Cole
May 23 '17 at 17:23
add a comment |
You can write a custom Mongoose validation method in this case. You can hook into post validation. Mongoose has validation and you can implement a hook before (pre) or after(post) validation. In this case, you can use post validation to see if the array is valid. Then just make sure the array has no duplications. There may be efficiency improvements you can make based upon your details. If you only have '_id' for example you could just use the JS includes function.
catSchema.post('validate',function(next) {
return new Promise((resolve,reject) => {
for(var i = 0; i < this.kittens.length; i++) {
let kitten = this.kittens[i];
for(var p = 0; p < this.kittens.length; p++) {
if (p == i) {
continue;
}
if (kitten._id == this.kittens[p]._id) {
return reject('Duplicate Kitten Ids not allowed');
}
}
}
return resolve();
});
});
I like to use promises in validation because it's easier to specify errors.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f6743849%2fmongodb-unique-index-on-array-elements-property%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
As far as I know, unique indexes only enforce uniqueness across different documents, so this would throw a duplicate key error:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
But this is allowed:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
I'm not sure if there's any way enforce the constraint you need at the Mongo level, maybe it's something you could check in the application logic when you insert of update?
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
add a comment |
As far as I know, unique indexes only enforce uniqueness across different documents, so this would throw a duplicate key error:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
But this is allowed:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
I'm not sure if there's any way enforce the constraint you need at the Mongo level, maybe it's something you could check in the application logic when you insert of update?
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
add a comment |
As far as I know, unique indexes only enforce uniqueness across different documents, so this would throw a duplicate key error:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
But this is allowed:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
I'm not sure if there's any way enforce the constraint you need at the Mongo level, maybe it's something you could check in the application logic when you insert of update?
As far as I know, unique indexes only enforce uniqueness across different documents, so this would throw a duplicate key error:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
But this is allowed:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
I'm not sure if there's any way enforce the constraint you need at the Mongo level, maybe it's something you could check in the application logic when you insert of update?
answered Jul 19 '11 at 8:18
Chris FulstowChris Fulstow
31.1k775100
31.1k775100
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
add a comment |
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
2
2
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
Unfortunately it seems like you're right - I'll have to enforce this in code. Oh well.
– Electric Monk
Jul 19 '11 at 22:36
7
7
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
So sad! :(. There should be an option to ensure uniqueness in document arrays.
– Juzer Ali
Aug 3 '12 at 19:06
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
What you can do is write validation hooks when saving in the array to ensure that it is unique
– Ouwen Huang
Nov 23 '14 at 7:53
add a comment |
Ensuring uniqueness of the individual values in an array field
In addition to the example above, there is a function in MongoDB to ensure that when you are adding a new object/value to an array field, that it will only perform the update if the value/object doesn't already exist.
So if you have a document that looks like this:
{ _id: 123, kittens: [456] }
This would be allowed:
db.cats.update({_id:123}, {$push: {kittens:456}})
resulting in
{ _id: 123, kittens: [456, 456] }
however using the $addToSet function (as opposed to $push) would check if the value already exists before adding it.
So, starting with:
{ _id: 123, kittens: [456] }
then executing:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Would not have any effect.
So, long story short, unique constraints don't validate uniqueness within the value items of an array field, just that two documents can't have identical values in the indexed fields.
add a comment |
Ensuring uniqueness of the individual values in an array field
In addition to the example above, there is a function in MongoDB to ensure that when you are adding a new object/value to an array field, that it will only perform the update if the value/object doesn't already exist.
So if you have a document that looks like this:
{ _id: 123, kittens: [456] }
This would be allowed:
db.cats.update({_id:123}, {$push: {kittens:456}})
resulting in
{ _id: 123, kittens: [456, 456] }
however using the $addToSet function (as opposed to $push) would check if the value already exists before adding it.
So, starting with:
{ _id: 123, kittens: [456] }
then executing:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Would not have any effect.
So, long story short, unique constraints don't validate uniqueness within the value items of an array field, just that two documents can't have identical values in the indexed fields.
add a comment |
Ensuring uniqueness of the individual values in an array field
In addition to the example above, there is a function in MongoDB to ensure that when you are adding a new object/value to an array field, that it will only perform the update if the value/object doesn't already exist.
So if you have a document that looks like this:
{ _id: 123, kittens: [456] }
This would be allowed:
db.cats.update({_id:123}, {$push: {kittens:456}})
resulting in
{ _id: 123, kittens: [456, 456] }
however using the $addToSet function (as opposed to $push) would check if the value already exists before adding it.
So, starting with:
{ _id: 123, kittens: [456] }
then executing:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Would not have any effect.
So, long story short, unique constraints don't validate uniqueness within the value items of an array field, just that two documents can't have identical values in the indexed fields.
Ensuring uniqueness of the individual values in an array field
In addition to the example above, there is a function in MongoDB to ensure that when you are adding a new object/value to an array field, that it will only perform the update if the value/object doesn't already exist.
So if you have a document that looks like this:
{ _id: 123, kittens: [456] }
This would be allowed:
db.cats.update({_id:123}, {$push: {kittens:456}})
resulting in
{ _id: 123, kittens: [456, 456] }
however using the $addToSet function (as opposed to $push) would check if the value already exists before adding it.
So, starting with:
{ _id: 123, kittens: [456] }
then executing:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Would not have any effect.
So, long story short, unique constraints don't validate uniqueness within the value items of an array field, just that two documents can't have identical values in the indexed fields.
answered Nov 17 '13 at 5:14
doublehelixdoublehelix
1,4141412
1,4141412
add a comment |
add a comment |
There is an equivalent of insert with uniquness in array attribute. The following command essentially does insert while ensuring the uniqueness of kittens (upsert creates it for you if the object with 123 doesn't already exist).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
The resulting value of the object will be
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}
The important properties are:$addToSet
andupsert
. The$set
property is unrelated to the OP.
– Michael Cole
May 23 '17 at 17:23
add a comment |
There is an equivalent of insert with uniquness in array attribute. The following command essentially does insert while ensuring the uniqueness of kittens (upsert creates it for you if the object with 123 doesn't already exist).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
The resulting value of the object will be
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}
The important properties are:$addToSet
andupsert
. The$set
property is unrelated to the OP.
– Michael Cole
May 23 '17 at 17:23
add a comment |
There is an equivalent of insert with uniquness in array attribute. The following command essentially does insert while ensuring the uniqueness of kittens (upsert creates it for you if the object with 123 doesn't already exist).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
The resulting value of the object will be
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}
There is an equivalent of insert with uniquness in array attribute. The following command essentially does insert while ensuring the uniqueness of kittens (upsert creates it for you if the object with 123 doesn't already exist).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
The resulting value of the object will be
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}
answered Nov 17 '16 at 6:18
timchunghttimchunght
18413
18413
The important properties are:$addToSet
andupsert
. The$set
property is unrelated to the OP.
– Michael Cole
May 23 '17 at 17:23
add a comment |
The important properties are:$addToSet
andupsert
. The$set
property is unrelated to the OP.
– Michael Cole
May 23 '17 at 17:23
The important properties are:
$addToSet
and upsert
. The $set
property is unrelated to the OP.– Michael Cole
May 23 '17 at 17:23
The important properties are:
$addToSet
and upsert
. The $set
property is unrelated to the OP.– Michael Cole
May 23 '17 at 17:23
add a comment |
You can write a custom Mongoose validation method in this case. You can hook into post validation. Mongoose has validation and you can implement a hook before (pre) or after(post) validation. In this case, you can use post validation to see if the array is valid. Then just make sure the array has no duplications. There may be efficiency improvements you can make based upon your details. If you only have '_id' for example you could just use the JS includes function.
catSchema.post('validate',function(next) {
return new Promise((resolve,reject) => {
for(var i = 0; i < this.kittens.length; i++) {
let kitten = this.kittens[i];
for(var p = 0; p < this.kittens.length; p++) {
if (p == i) {
continue;
}
if (kitten._id == this.kittens[p]._id) {
return reject('Duplicate Kitten Ids not allowed');
}
}
}
return resolve();
});
});
I like to use promises in validation because it's easier to specify errors.
add a comment |
You can write a custom Mongoose validation method in this case. You can hook into post validation. Mongoose has validation and you can implement a hook before (pre) or after(post) validation. In this case, you can use post validation to see if the array is valid. Then just make sure the array has no duplications. There may be efficiency improvements you can make based upon your details. If you only have '_id' for example you could just use the JS includes function.
catSchema.post('validate',function(next) {
return new Promise((resolve,reject) => {
for(var i = 0; i < this.kittens.length; i++) {
let kitten = this.kittens[i];
for(var p = 0; p < this.kittens.length; p++) {
if (p == i) {
continue;
}
if (kitten._id == this.kittens[p]._id) {
return reject('Duplicate Kitten Ids not allowed');
}
}
}
return resolve();
});
});
I like to use promises in validation because it's easier to specify errors.
add a comment |
You can write a custom Mongoose validation method in this case. You can hook into post validation. Mongoose has validation and you can implement a hook before (pre) or after(post) validation. In this case, you can use post validation to see if the array is valid. Then just make sure the array has no duplications. There may be efficiency improvements you can make based upon your details. If you only have '_id' for example you could just use the JS includes function.
catSchema.post('validate',function(next) {
return new Promise((resolve,reject) => {
for(var i = 0; i < this.kittens.length; i++) {
let kitten = this.kittens[i];
for(var p = 0; p < this.kittens.length; p++) {
if (p == i) {
continue;
}
if (kitten._id == this.kittens[p]._id) {
return reject('Duplicate Kitten Ids not allowed');
}
}
}
return resolve();
});
});
I like to use promises in validation because it's easier to specify errors.
You can write a custom Mongoose validation method in this case. You can hook into post validation. Mongoose has validation and you can implement a hook before (pre) or after(post) validation. In this case, you can use post validation to see if the array is valid. Then just make sure the array has no duplications. There may be efficiency improvements you can make based upon your details. If you only have '_id' for example you could just use the JS includes function.
catSchema.post('validate',function(next) {
return new Promise((resolve,reject) => {
for(var i = 0; i < this.kittens.length; i++) {
let kitten = this.kittens[i];
for(var p = 0; p < this.kittens.length; p++) {
if (p == i) {
continue;
}
if (kitten._id == this.kittens[p]._id) {
return reject('Duplicate Kitten Ids not allowed');
}
}
}
return resolve();
});
});
I like to use promises in validation because it's easier to specify errors.
answered Dec 28 '18 at 13:35
David JDavid J
56638
56638
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f6743849%2fmongodb-unique-index-on-array-elements-property%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
See stackoverflow.com/questions/4435637/…
– pingw33n
Jul 19 '11 at 8:19