How to generate unique id for each element of an array field in MongoDB - mongodb

How to create a unique ID for each element of an array field, where uniqueness is maintained globally for all documents of the collection?
Is it possible to specify create a unique index for this field?

You can make use of ObjectId data type. ObjectIds are 12-byte values that are guaranteed to be unique across all documents in a collection. You can specify an ObjectId as the value for a field in an array when inserting a new document.
For example, if you have following document:
{
_id: ObjectId("5f9b5a6d65c5f09f7b5a6d65"),
nameOfArrayField: []
}
You can use the following command to insert a new document:
db.collection.insertOne({
nameOfArrayField: [
{
id: new ObjectId(),
name: "Big Cat Public Safety Law"
}
]
});
To specify a unique index, you can use createIndex() method in the MongoDB shell.
db.collection.createIndex({ "nameOfArrayField.id": 1 }, { unique: true })
unique: true option ensures that the id field of the element array will be unique globally for all documents of the collection. It will prevent from inserting the duplicate element with the same id field in the array. Point to be noted that it is an asynchronous operation. You can use the db.collection.getIndexes() method to check if the index is created or not.

Related

Unique multikey in mongodb for field of array of embedded fields

I have this Document structure:
id: "xxxxx",
name: "John",
pets: [
{
"id": "yyyyyy",
"type": "Chihuahua",
},
{
"id": "zzzzzz",
"type": "Labrador",
}
]
The pets field is not an array of embedded documents (not referencing any other collection).
I want the pets id to be unique across the documents and the document itself, but it seems the mongodb official docs say its not possible and doesnt offer other solution:
For unique indexes, the unique constraint applies across separate documents in the collection rather than within a single document.
Because the unique constraint applies to separate documents, for a
unique multikey index, a document may have array elements that result
in repeating index key values as long as the index key values for that
document do not duplicate those of another document.
https://docs.mongodb.com/manual/core/index-multikey/
I have tried this using mongodb golang driver:
_, err = collection.Indexes().CreateOne(context.TODO(), mongo.IndexModel{
Keys: bson.M{"pets.id": 1},
Options: options.Index().SetUnique(true),
})
but like the docs said, it allows 2 pets of a person to have same ID, while not allowing a pet from a different person to have the same ID compared to the pet of the first person...
is there anyway to enforce this in mongodb ?

MongoDB new ObjectId over array giving me same Id for all

I am trying to update items in an array with unique ObjectIds (meaning add an object ID to array object that are missing them)
If I have an array of shirt objects in my collection and I try this:
db.people.update({
$and : [
_id: ObjectId('5eeb44c6a042791d28a8641f'),
{
$or: [
{ 'shirts._id': { $eq:null } },
{ 'shirts._id':{ $exists:false } }
]
}
]
},{
$set: { 'shirts.$[]._id': new ObjectId() }
},{
"multi" : true
}
);
It generates IDENTICAL ObjectsIDs for each array element, I would put an unique index on this however, the use case probably wont see more then 2-3 items in the array with edge cases hitting 5-6, which seems like an abuse of an index
How can I update multiple records or multiple array objects with a unique ObjectId?
When you use $set you're telling mongo to set that value to all matching elements. If the elements in the array are already defined as schemas, mongo will issue new ObjectIds for each one of them automatically.
Alternatively, you can use forEach and iterate over each matching element creating a new ObjectId.

Why is my MongoDb query inserting an embedded document on Update?

This is my MongoDB query:
db.events.update({date:{$gte: ISODate("2014-09-01T00:00:00Z")}},{$set:{"artists.$.soundcloud_toggle":false}},{multi:true,upsert:false})
Apparently I cannot use "artists.$.soundcloud_toggle" to update all artist documents within the artists array:
"The $ operator can update the first array element that matches
multiple query criteria specified with the $elemMatch() operator.
http://docs.mongodb.org/manual/reference/operator/update/positional/"
I'm happy to run the query a number of times changing the index of the array in order to set the soundcloud_toggle property of every artist in every event that matches the query e.g
artists.0.soundcloud_toggle
artists.1.soundcloud_toggle
artists.2.soundcloud_toggle
artists.3.soundcloud_toggle
The problem is: when there is say, only one artist document in the artists array and I run the query with "artists.1.soundcloud_toggle" It will insert an artist document into the artist array with a single property:
{
"soundcloud_toggle" : true
},
(I have declared "upsert:false", which should be false by default anyways)
How do I stop the query from inserting a document and setting soundcloud_toggle:false when there is no existing document there? I only want it to update the property if an artist exists at the given artists array index.
If, like you said, you don't mind completing the operation with multiple queries, you can add an $exists condition to your filter.
E.g. in the 5th iteration, when updating index=4, add: "artists.4": {$exists: true}, like:
db.events.update(
{ date: {$gte: ISODate("2014-09-01T00:00:00Z")},
"artists.4": {$exists: true} },
{ $set:{ "artists.4.soundcloud_toggle" :false } },
{ multi: true, upsert: false }
)

Clone MongoDB objects in Meteorjs by changing value of a single field

I am working on a Meteorjs application which is using MongoDB in back end.
In my collection there are some objects which are having a common field named parent_id eg
{name:'A',parent_id:'acd'}
{name:'b',parent_id:'acd'}
{name:'c',parent_id:'acd'}
{name:'d',parent_id:'acd'}
I want to copy all these objects in the database by changing the parent_id field eg
{name:'A',parent_id:'acdef'}
{name:'b',parent_id:'acdef'}
{name:'c',parent_id:'acdef'}
{name:'d',parent_id:'acdef'}
and these all objects will be in database like this
{name:'A',parent_id:'acd'}
{name:'b',parent_id:'acd'}
{name:'c',parent_id:'acd'}
{name:'d',parent_id:'acd'}
{name:'A',parent_id:'acdef'}
{name:'b',parent_id:'acdef'}
{name:'c',parent_id:'acdef'}
{name:'d',parent_id:'acdef'}
for this I have find the elements from the db which have parent_id:'abc'
items=db.collection.find({parent_id:'abc').fetch()
and using a loop i have changed the parent_id of each item and then tried this command
for(i=0;i<items.length;i++){
items[i].parent_id='abcdef';
meteor.collection.insert(item)
}
but it is giving me an errorduplicate for _id
Well it will unless you delete the _id value from the object first:
for(i=0;i<items.length;i++){
items[i].parent_id='abcdef';
delete items[i]["_id"];
meteor.collection.insert(item[i])
}
So the delete should clear that up and an new _id will be generated.
When you Collection.find() your documents you can use the field specifier to exclude the _id field.
var items = collection.find({}, {fields: {name: 1, parent_id: 1, _id: 0}).fetch();
Then when you modify and insert those documents again, they will be duplicates with each having its own unique _id.

Generating a new Mongo object id for each document in a collection?

How do you go about creating a unique object id for each document in a mass update?
I've tried,
db.foo.update({ objectId: null }, { $set: { objectId: new ObjectId() }}, { multi: true })
But that gives me the same object id for each document.
Because you're applying a unique value to each doc, you need to iterate over your collection and update the docs one at a time.
In the shell:
db.foo.find({ objectId: null }).forEach(function(doc) {
doc.objectId = new ObjectId();
db.foo.save(doc);
});
You cannot update multiple documents in a single command in MongoDb currently. You can update multiple documents with a common set of changes/updates, but you can not make unique changes to each document. You would need to create a loop to iterate over each document in the shell or your favorite programming language.
You can generate an object Id in MongoDB like this. You can iterate over your doc and use this mongo object id.
const ObjectId = require("mongodb").ObjectID;
const id = new ObjectId
console.log(id)