MongoDB weird writeResult behaviour - mongodb

I am using mongodb (v2.6.7) and mongo (2.6.7) shell client.
I am trying to use the WriteResult object returned by the insert and and update commands.
According to mongodocs in case of error it returns a writeResult object with writeError subdocument. But I am not able to access this subdocument in shell or in mongo's javascript file.
Below is an illustration of my problem.
I insert an object and get the successful writeResult.
Then I am inserting again with the same _id and I am getting the writeResult correctly printed on the screen which has "writeError" correctly set.
Also the writeResult object seems to contain the writeError when I print it with printjson() method
But when I print it with JSON.stringify() then I am not able to see the "writeError".
Also writeResult.writeError is coming as undefined so I am not able to access its writeResult.writeError.code property.
Can someone please explain why is this happening and what is the correct way.
afv:PRIMARY>writeResult=db.sysinfo.insert({_id:"myid",otherData:"otherDataValue"})
WriteResult({ "nInserted" : 1 })
afv:PRIMARY>writeResult=db.sysinfo.insert({_id:"myid",otherData:"otherDataValue"})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: afvadmin.sysinfo.$_id_ dup key: { : \"myid\" }"
}
})
afv:PRIMARY> printjson(writeResult)
{
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: afvadmin.sysinfo.$_id_ dup key: { : \"myid\" }"
}
}
afv:PRIMARY> JSON.stringify(writeResult);
{"nInserted":0,"nUpserted":0,"nMatched":0,"nModified":0,"nRemoved":0}
afv:PRIMARY> writeResult.writeError
afv:PRIMARY> writeResult.nInserted
0
afv:PRIMARY> writeResult.writeError.code
2015-02-02T16:34:42.402+0530 TypeError: Cannot read property 'code' of undefined
afv:PRIMARY> writeResult["writeError"]

I don't know why it was implemented this way, but to access the contained writeError subdocument, you call getWriteError() on a WriteResult object:
> writeResult.getWriteError()
WriteError({
"index": 0,
"code": 11000,
"errmsg": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.test.$_id_ dup key: { : \"myid\" }",
"op": {
"_id": "myid",
"otherData": "otherDataValue"
}
})
> writeResult.getWriteError().code
11000
I couldn't find any documentation for this. I figured it out by hitting Tab twice after typing writeResult. in the shell to see what's available.

In addition to using the methods to get the WriteError object as mentioned already, you can also get the raw response and work on that:
> writeResult.getRawResponse()
{
"writeErrors" : [
{
"index" : 0,
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: foo.bar.$_id_ dup key: { : ObjectId('54cf8152733aa5e886f0e400') }",
"op" : {
"_id" : ObjectId("54cf8152733aa5e886f0e400"),
"a" : 1
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 0,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
}
So, you can then do something like this and things are a bit more consistent:
> raw = writeResult.getRawResponse();
> raw.writeErrors[0].errmsg
insertDocument :: caused by :: 11000 E11000 duplicate key error index: foo.bar.$_id_ dup key: { : ObjectId('54cf8152733aa5e886f0e400') }
> printjson(raw.writeErrors[0])
{
"index" : 0,
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: foo.bar.$_id_ dup key: { : ObjectId('54cf8152733aa5e886f0e400') }",
"op" : {
"_id" : ObjectId("54cf8152733aa5e886f0e400"),
"a" : 1
}
}
> JSON.stringify(raw.writeErrors[0])
{"code":11000,"index":0,"errmsg":"insertDocument :: caused by :: 11000 E11000 duplicate key error index: foo.bar.$_id_ dup key: { : ObjectId('54cf8152733aa5e886f0e400') }"}

Related

Mongo Db update failing while using $Set for a null valued field

I am trying to update an existing document which has a field with null value in it and I am getting the following error.
Document:
{
"_id" : ObjectId("582299f71e21dbf65027325e"),
"b" : "5555",
"f" : null
}
Query:
db.getCollection('temp').update({"b":"5555"},{"$set":{"f.1.b":1,"f.2.b":2}})
Error:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 16837,
"errmsg" : "cannot use the part (f of f.1.b) to traverse the element ({f: null})"
}
})
Anyone can tell me why it was not updating the value in the document.
Thank you.
Because there are no f.1.b and f.2.b object found to set
In this case you can try this
Prepare a proper object and try to set
Eg :
var temp = {
1 : {b: 1},
2: {b : 2}
}
db.getCollection('temp').update({"b":"5555"},{"$set":{f:temp}})

Unique documents in a MongoDB collection

I need to store three id:s in a document but they can only occur once. For example the document below can only occur once in this collection:
{
"user": ObjectId("j8uwh902w5489"),
"comment": ObjectId("09890583457jkjsf4"),
"whatever": ObjectId("j8uwh902w5489")
}
How do I make sure this will be a unique document in MongoDB?
Well you can use MongoDB's Unique Compound Index
db.users.createIndex( { user: 1, comment: 1, whatever: 1 }, { unique: true } )
A few Cases:
> db.users.insert({user: "A", comment: "B", whatever: "C"})
WriteResult({ "nInserted" : 1 })
> db.users.insert({user: "A", comment: "C", whatever: "B"})
WriteResult({ "nInserted" : 1 })
> db.users.insert({user: "A", comment: "B", whatever: "C"})
> WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.users.$user_1_comment_1_whatev
er_1 dup key: { : \"A\", : \"B\", : \"C\" }"
}
})
I know I have used strings here. But something similar might also be possible with ObjectIds. Please do give it a try.

Indexing array/subobject in mongoDB causes duplicate key error

I have a collection where I will have a _children attribute like this:
{
_children: {
videoTags: [ { id: '1', name: 'one'}, { id: '2', name: 'two'} ],
},
a: 10
}
Since I WILL search in videoTags, I create an index as such:
> db.test4.createIndex({ "_children.videosTags.id" : 1 }, { "unique" : true } );
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
Trouble is, I can no longer add anything to that table since I get a duplicate index error. Here is how to reproduce it:
Step 1: insert to a collection
db.test4.insert({a:20})
WriteResult({ "nInserted" : 1 })
Step 2: make the index
db.test4.createIndex({ "_children.videosTags.id" : 1 }, { "unique" : true } );
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
Step 3: try to insert again
db.test4.insert({a:30})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: wonder_1.test4.$_children.videosTags.id_1 dup key: { : null }"
}
})
I think the issue here is that there is already a record where _children.videoTags.id is not defined.
However, what I expected was a behaviour where if videoTags.id was specified, it needed to be unique. Instead, an empty one is considered a "taken" key.
What am I doing that is stupidly wrong?
This will work if you don't set unique as true, but I have the feeling I need to fix it for real...
There could be two reasons.
There could be other documents exists in collection with same _children.videosTags.id
It's quite possible that more than one document may have missing _children.videosTags.id" or having null value.
As you are creating unique key, null or empty values are give you tough time. Solution is either create sparse index and if your MongoDB version is 3.2+, create partial index. See documentation for partial indexes.

Get back BulkWriteError from the Mongo shell

I want to store writeErrors documents into another collection in MongoDB while performing a bulk.execute(). I am basically doing a bulk insert/update but want to capture all the errors into another collection in parallel to the bulk operation.
I can see the BulkWriteError object is returned in Mongo-Shell, I can also see the writeErrors array in the object. But how can I capture it?
In accordance with https://github.com/mongodb/mongo/blob/master/src/mongo/shell/bulk_api.js (line 363):
// Bulk errors are basically bulk results with additional error information
BulkWriteResult.apply(this, arguments);
So you can use the BulkWriteResult.getWriteErrors() method.
try {
bulk.execute();
...
} catch(err) {
if ("name" in err && err.name == 'BulkWriteError') {
var wErrors = err.getWriteErrors();
wErrors.forEach(function(doc){
db.errlog.insert(doc);
});
}
}
I can see the BulkWriteError object is returned in Mongo-Shell
It is not returned. This is a raised exception. You need a try...catch block to get it back:
> bulk = db.w.initializeUnorderedBulkOp();
> bulk.insert({_id:1})
> bulk.insert({_id:1})
> try { result = bulk.execute() } catch(e) { err = e }
> err
BulkWriteError({
"writeErrors" : [
{
"index" : 1,
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.w.$_id_ dup key: { : 1.0 }",
"op" : {
"_id" : 1
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 1,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
Surprisingly enough, it is rather painful to store the BulkWriteError in a collection. One easy way of doing (not necessary an elegant way, though) is to parse the JSON representation of the error to get back the field(s) that interest you.
> db.errlog.insert(JSON.parse(err.tojson()).writeErrors)
// ^^^^^^^^^^^^^^^^^^^^^^^^
// parse the JSON representation of `BulkWriteError`
That way, you get back the array of write errors, that insert will happily store in the collection:
> db.errlog.find().pretty()
{
"_id" : ObjectId("55619737c0c8238aef6e21c5"),
"index" : 0,
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.w.$_id_ dup key: { : 1.0 }",
"op" : {
"_id" : 1
}
}

dropDups true not working mongodb

I am using mongoDB shell with version 3.0.2
I am trying to ensure uniqueness constraint over a username field in collection users.
This is what I gave:
db.users.ensureIndex({"username": 1},{unique: true})
It gave me following error:
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"errmsg" : "exception: E11000 duplicate key error index: mybackend.users.$username_1 dup key: { : \"rahat\" }",
"code" : 11000,
"ok" : 0
}
Then i used, dropDups: true in the command:
db.users.ensureIndex({"username": 1},{unique: true, dropDups: true})
Then too I get the same error:
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"errmsg" : "exception: E11000 duplicate key error index: mybackend.users.$username_1 dup key: { : \"rahat\" }",
"code" : 11000,
"ok" : 0
}
I also saw this SO link but here it already had one index. Mine does not have one.
db.users.getIndexes() ->
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "mybackend.users"
}
]
I looked for this issue on github and restarted the mongo but to no use. What am I doing wrong? I think I am doing a silly mistake. Please help.
The drop duplicates functionality on index creation is no longer supported since Mongo version 3.0. See the compatibility changes page for the 3.0 release.