Manually change MongoID - mongodb

Through the PHP problem when inserting stuff into MongoDB explained in the answer by Denver Matt in this question I created duplicate IDs in a dataset in MongoDB. Fixing the PHP code is easy, but to be able to still use my dataset I wonder:
Can I change the MongoId manually without breaking something? Or can I just reset this ID somehow into a new one?

The _id field of a document is immutable, as discussed in this documentation. Attempting to modify its value would result in an error/exception, as in:
> db.foo.drop()
> db.foo.insert({ _id: 1 })
> db.foo.update({ _id: 1 }, { $set: { _id: 3 }})
Mod on _id not allowed
> db.foo.find()
{ "_id" : 1 }
If you do need to alter the identifier of a document, you could fetch it, modify the _id value, and then re-persist the document using insert() or save(). insert() may be safer on the off chance that you new _id value conflicts and you're rather see a uniqueness error than overwrite the existing document (as save() would do). Afterwards, you'll need to go back and remove the original document.
Since you can't do all of this in a single atomic transaction, I would suggest the following order of operations:
findOne() existing document by its _id
Modify the returned document's _id property
insert() the modified document back into the collection
If the insert() succeeded, remove() the old document by the original _id

Related

MongoDB creating index on a new field

I need to create a TTL Index in MongoDB and for that, I'm adding a new field "last_modified". I'm using the latest Python and pymongo in case this makes any difference.
After reading information on sparse and non-sparse indexes I understand that all documents that do not have "last_modified" will have this field added with the null value.
Is there a way to set some default value instead of null for those documents?
Alternatively, I'll have to update all documents in all DB instances using some migration function, but I would really like to do it clean...
Thanks in advance for any links or ideas!
I understand that all documents that do not have "last_modified" will have this field added with the null value.
No this is not true, sparse indexes just index documents where the field exists. documents without this field will just be out of the index converage.
Is there a way to set some default value instead of null for those documents? ... I'll have to update all documents in all DB instances ... to do it clean...
You have to run an update, there is no magic solution. Not sure why doing this is "not clean".
The update is super simple:
// this query will allow you to execute the update even if you started streaming new events with this field.
db.collection.updateMany({ last_modified: {$exists: false} }, { $set: { last_modified: defaultValue }})

MongoDB Save and update

While reading about Mongo Save and Update ,I got bit confuse -as per article
MongoDB's update() and save() methods are used to update document into a collection. The update() method update values in the existing document while the save() method replaces the existing document with the document passed in save() method.
Please let me know difference in both .
update changes an existing document found by your find-parameters and does nothing when no such document exist (unless you use the upsert option).
save doesn't allow any find-parameters. It checks if there is a document with the same _id as the one you save exists. When it exists, it replaces it. When no such document exists, it inserts the document as a new one. When the document you insert has no _id field, it generates one with a newly created ObjectId before inserting.
collection.save(document); is basically a shorthand for:
if (document._id == undefined) {
document._id = new ObjectId();
}
collection.update({ "_id":document._id }, document, { upsert:true });
From the documentation:
Save command.
The save() method uses either the insert or the update command, which
use the default write concern. To specify a different write concern,
include the write concern in the options parameter.
If the document does not contain an _id field, then the save() method
calls the insert() method.
If the document contains an _id field, then the save() method is
equivalent to an update with the upsert option set to true and the
query predicate on the _id field.
Update command
if upsert is not specified it
Modifies an existing document or documents in a collection. The method
can modify specific fields of an existing document or documents or
replace an existing document entirely, depending on the update
parameter.
If upsert is true and no document matches the query criteria, update()
inserts a single document.
So they are pretty similar and both can update and insert the document. The difference is that save can update only one document.

Update value in MongoDB

I have to add new value (or edit actual) company. I tried this code in console:
db.users.update({email: /debute/},{company: "test"})
But now, in database I have only _id and company. Why other values removed? Or how can I prevent of removing other values in future?
By default, the update function replaces the entire document with the document you pass. But you can also use it to only replace individual fields and leave the others alone by using the $set operator.
db.users.update({email: /debute/},{ $set: { company: "test"} } );
You might also want to specify a third argument { multi: true } to the update. Otherwise it will only update the first document it finds which matches the condition.
You need to use an update operator on order to update an existing document, your code replaces the document with the new document. Here is how to do an update:
db.users.update({email: /debute/},{$set: {company: "test"}})

Find the collection name from document._id in meteor (mongodb)

From the looks of the syntax for handling mongodb related things in meteor it seems that you always need to know the collection's name to update, insert, remove or anything to the document.
What I am wondering is if it's possible to get the collection's name from the _id field of a document in meteor.
Meaning if you have a document with the _id equal to TNTco3bHzoSFMXKJT. Now knowing the _id of the document you want to find which collection the document is located in. Is this possible through meteor's implementation of mongodb or vanilla mongodb?
As taken from the official docs:
idGeneration String
The method of generating the _id fields of new documents in this collection. Possible values:
'STRING': random strings
'MONGO': random Meteor.Collection.ObjectID values
The default id generation technique is 'STRING'.
Your best option would be to insert records within a pseudo transaction where the second step is to take the id and collection name to feed it into a reference collection. Then, you can do your lookups from that.
It would be pretty costly, though to construct your find's but might be a pattern worthwhile exploring if you are building an app where your users will be creating arbitrary data patterns.
You could accomplish this by doing a findOne on all of the collections:
var collectionById = function(id) {
return _.find(_.keys(this), function(name) {
if (this[name] instanceof Meteor.Collection) {
if (this[name].findOne(id)) {
return true;
}
}
});
};
I tested this on both the client and the server and it seemed to work when run in the global context.

Does Mongo have versioning on objects (like ElasticSearch)

Does Mongo automatically track a version which is incremented for each update and can be used for optimistic locking?
So something that would correspond to functionality described here in ElasticSearch http://www.elasticsearch.org/blog/elasticsearch-versioning-support/
No, MongoDB does not store versions of documents. There is only the "current" version of the document as far as the database API is concerned.
It would be necessary to create your own scheme if you wanted such a thing. You could use a version field in your document and use $inc for example to increment it as needed and also verify that the version value matched before applying an update.
Example:
db.myCollection.update(
{ _id: "abc123", _version: 5 },
{
$set: { 'fieldA' : 'some-value' },
$inc: { '_version' : 1 }
}
)
The above example would find a document with the specific _id and _version fields. If matched, a field called fieldA is set to a new value and the _version field is incremented by 1. If another update was attempted on the same document and version, it would fail as the _version would have been updated to 6.