MongoDB queries with null value - mongodb

My collection (MongoDB v 2.0.2) has following records:
db.organization.find({})
{ "_id" : 1001, "path" : [ ], "parent" : null }
{ "_id" : 1002, "path" : [ 1001 ], "parent" : NumberLong(1001) }
organization has indexes:
db.organization.ensureIndex({"path":1});
db.organization.ensureIndex({"parent":1},{sparse:false});
(note I put awarnes sparse : false - to grant that null is indexed)
But, executing:
db.organization.find({"parent":null})
Returns empty set. What is wrong? Thank you in advance

I had the same issue. After reading the following documents
querying and nulls
BSON specification
I tried to query for the different BSON element types and found that my null was represented as a BSON element type 6 (undefined, deprecated) instead of the expected BSON element type 10 (null).
db.collection.find({ field: { "$type" : 6} };

Just checked following script at 2.0 and 2.0.2:
db.items.insert({ "_id" : 1001, "path" : [ ], "parent" : null })
db.items.insert({ "_id" : 1002, "path" : [ 1001 ], "parent" : NumberLong(1001) })
db.items.ensureIndex({"path":1});
db.items.ensureIndex({"parent":1},{sparse:false});
db.items.find({"parent":null})
actually returns one document that you expect:
{ "_id" : 1001,
"path" : [],
"parent" : null }
Also you can look into this doc about querying and nulls, probably should help you avoid possible future mistakes.

Related

What are the efficient query for mongodb if value exist on array then don't update and return the error that id already exist

I have an entry stored on my collection like this:
{
"_id" : ObjectId("5d416c595f19962ff0680dbc"),
"data" : {
"a" : 6,
"b" : [
"5c35f04c4e92b8337885d9a6"
]
},
"image" : "123.jpg",
"hyperlinks" : "google.com",
"expirydate" : ISODate("2019-08-27T06:10:35.074Z"),
"createdate" : ISODate("2019-07-31T10:24:25.311Z"),
"lastmodified" : ISODate("2019-07-31T10:24:25.311Z"),
"__v" : 0
},
{
"_id" : ObjectId("5d416c595f19962ff0680dbd"),
"data" : {
"a" : 90,
"b" : [
"5c35f04c4e92b8337885d9a7"
]
},
"image" : "456.jpg",
"hyperlinks" : "google.com",
"expirydate" : ISODate("2019-08-27T06:10:35.074Z"),
"createdate" : ISODate("2019-07-31T10:24:25.311Z"),
"lastmodified" : ISODate("2019-07-31T10:24:25.311Z"),
"__v" : 0
}
I have to write the query for push userid on b array which is under data object and increment the a counter which is also under data object.
For that, I wrote the Code i.e
db.collection.updateOne({_id: ObjectId("5d416c595f19962ff0680dbd")},
{$inc: {'data.a': 1}, $push: {'data.b': '124sdff54f5s4fg5'}}
)
I also want to check that if that id exist on array then return the response that following id exist, so for that I wrote extra query which will check and if id exist then return the error response that following id exist,
My question is that any single query will do this? Like I don't want to write Two Queries for single task.
Any help is really appreciated for that
You can add one more check in the update query on "data.b". Following would be the query:
db.collection.updateOne(
{
_id: ObjectId("5d416c595f19962ff0680dbd"),
"data.b":{
$ne: "124sdff54f5s4fg5"
}
},
{
$inc: {'data.a': 1},
$push: {'data.b': '124sdff54f5s4fg5'}
}
)
For duplicate entry, you would get the following response:
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }
If matched count is 0, you can show the error that the id already exists.
You can use the operator $addToSet to check if the element already exits in the array.
db.collection.updateOne({_id: ObjectId("5d416c595f19962ff0680dbd")},
{$inc: {'data.a': 1}, $addToSet: {'data.b': '124sdff54f5s4fg5'}}
)

Mongodb aggregate lookup return only one field of array

i have some collections for our project.
Casts collection contains movie casts
Contents collection contains movie contents
i want to run aggregate lookup for get information about movie casts with position type.
i removed collections details unnecessary fields.
Casts details:
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_name" : "",
"en_name" : "Ehsan",
"fa_bio" : "",
"en_bio" : ""
}
Contents details:
{
"_id" : ObjectId("5a6b8b734f1408137f79e2cc"),
"casts" : [
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_fictionName" : "",
"en_fictionName" : "Ehsan2",
"positionType" : {
"id" : 3,
"fa_name" : "",
"en_name" : "Director"
}
},
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_fictionName" : "",
"en_fictionName" : "Ehsan1",
"positionType" : {
"id" : 3,
"fa_name" : "",
"en_name" : "Writers"
}
}
],
"status" : 0,
"created" : Timestamp(1516997542, 4),
"updated" : Timestamp(1516997542, 5)
}
when i run aggregate lookup with bellow query, in new generated lookup array only one casts contents If in accordance with above casts array value aggregate lookup should return two casts content with two type. in casts array value exists two type of casts, 1) writers and directors. but returned director casts content. _casts should contains two object not one object!
aggregate lookup query:
{$lookup:{from:"casts",localField:"casts._id",foreignField:"_id",as:"_casts"}}
result:
{
"_id" : ObjectId("5a6b8b734f1408137f79e2cc"),
"casts" : [
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_fictionName" : "",
"en_fictionName" : "Ehsan2",
"positionType" : {
"id" : 3,
"fa_name" : "",
"en_name" : "Director"
}
},
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_fictionName" : "",
"en_fictionName" : "Ehsan1",
"positionType" : {
"id" : 3,
"fa_name" : "",
"en_name" : "Writers"
}
}
],
"_casts" : [
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"fa_name" : "",
"en_name" : "Ehsan",
"fa_bio" : "",
"en_bio" : ""
}
],
"status" : 0,
"created" : Timestamp(1516997542, 4),
"updated" : Timestamp(1516997542, 5)
}
EDIT-1
finally my problem is solved. i have only one problem with this query, this query doesn't show root document fields. finally solve this problem. finally query exists in EDIT-2.
query:
db.contents.aggregate([
{"$unwind":"$casts"},
{"$lookup":{"from":"casts","localField":"casts._id","foreignField":"_id","as":"casts.info"}},
{"$unwind":"$casts.info"},
{"$group":{"_id":"$_id", "casts":{"$push":"$casts"}}},
])
EDIT-2
db.contents.aggregate([
{"$unwind":"$casts"},
{"$lookup":{"from":"casts","localField":"casts._id","foreignField":"_id","as":"casts.info"}},
{"$unwind":"$casts.info"},
{$group:{"_id":"$_id", "data":{"$first":"$$ROOT"}, "casts":{"$push":"$casts"}}},
{$replaceRoot:{"newRoot":{"$mergeObjects":["$data",{"casts‌​":"$casts"}]}}},
{$project:{"casts":0}}
]).pretty()
This is expected behavior.
From the docs,
If your localField is an array, you may want to add an $unwind stage
to your pipeline. Otherwise, the equality condition between the
localField and foreignField is foreignField: { $in: [
localField.elem1, localField.elem2, ... ] }.
So to join each local field array element with foreign field element you have to $unwind the local array.
db.content.aggregate([
{"$unwind":"$casts"},
{"$lookup":{"from":"casts","localField":"casts._id","foreignField":"_id","as":"_casts"}}
])
Vendor Collection
Items Collection
db.items.aggregate([
{ $match:
{"item_id":{$eq:"I001"}}
},
{
$lookup:{
from:"vendor",
localField:"vendor_id",
foreignField:"vendor_id",
as:"vendor_details"
}
},
{
$unwind:"$vendor_details"
},
{
$project:{
"_id":0,
"vendor_id":0,
"vendor_details.vendor_company_description":0,
"vendor_details._id":0,
"vendor_details.country":0,
"vendor_details.city":0,
"vendor_details.website":0
}
}
]);
Output
Your Casts collection shows only 1 document. Your Contents collection, likewise, shows only 1 document.
This is 1 to 1 - not 1 to 2. Aggregate is working as designed.
The Contents document has 2 "casts." These 2 casts are sub-documents. Work with those as sub-documents, or re-design your collections. I don't like using sub-documents unless I know I will not need to use them as look-ups or join on them.
I would suggest you re-design your collection.
Your Contents collection (it makes me think of "Movies") could look like this:
_id
title
releaseDate
genre
etc.
You can create a MovieCasts collection like this:
_id
movieId (this is _id from Contents collection, above)
castId (this is _id from Casts collection, below)
Casts
_id
name
age
etc.

Updating nested List in mongoDB Query working sometimes but with large data set it fails [duplicate]

This question already has answers here:
Updating a Nested Array with MongoDB
(2 answers)
Closed 5 years ago.
Following is a MongoDB document:
{
"_id" : 2,
"mem_id" : M002,
"email" : "xyz#gmail.com",
"event_type" : [
{
"name" : "MT",
"count" : 1,
"language" : [
{
"name" : "English",
"count" : 1,
"genre" : [
{
"name" : "Action",
"count" : 6
},
{
"name" : "Sci-Fi",
"count" : 3
}
],
"cast" : [
{
"name" : "Sam Wortington",
"count" : 2
},
{
"name" : "Bruce Willis",
"count" : 4
},
{
"name" : "Will Smith",
"count" : 7
},
{
"name" : "Irfan Khan",
"count" : 1
}
]
}
]
}
]
}
I'm not able to update fields that is of type array, specially event_type, language, genre and cast because of nesting. Basically, I wanted to update all the four mentioned fields along with count field for each and subdocuments. The update statement should insert a value to the tree if the value is new else should increment the count for that value.
What can be the query in mongo shell?
Thanks
You are directly hitting one of the current limitations of MongoDB.
The problem is that the engine does not support several positional operators.
See this Multiple use of the positional `$` operator to update nested arrays
There is an open ticket for this: https://jira.mongodb.org/browse/SERVER-831 (mentioned also there)
You can also read this one on how to change your data model: Updating nested arrays in mongodb
If it is feasible for you, you can do:
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.0.language.$.count":<number>}})
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.$.language.0.count":<number>}})
But you cannot do:
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.$.language.$.count":<number>}})
Let's take case by case:
To update the field name in event_type array:
db.testnested.update({"event_type.name" : "MT"}, {$set : {"event_type.name" : "GMT"}})
This command will update the name for an object inside the event_type list, to GMT from MT:
BEFORE:
db.testnested.find({}, {"event_type.name" : 1})
{ "_id" : 2, "event_type" : [ { "name" : "MT" } ] }
AFTER:
db.testnested.find({}, {"event_type.name" : 1})
{ "_id" : 2, "event_type" : [ { "name" : "GMT" } ] }
2.To update fields inside event_type, such as language, genre that are intern list:
There is no direct query for this. You need to read the document, update that document using the JavaScript or language of your choice, and then save() the same. I dont think there is any other way available till mongo 2.4
For further documentation, you can refer to save().
Thanks!

Error while looping pymongo object

I have a collection like.
{
"id" : 101,
"name" : "ragav",
"address" : "143 karnadaka",
"products" : [
{
"id" : 2,
"name" : "AA",
"amount" : "150"
},
{
"id" : 4,
"name" : "BB",
"amount" : "15"
},
{
"id" : 6,
"name" : "CC",
"amount" : "210"
},
]
}
I need to find a record in this collection based on product. I running the following query.
Query
db.Response.find(
{"products.id":2},
{"products.id.$":1,"id":1,"name":1,"address":1}
)
In my mongo terminal i got the output. But i accessing through python using pymongo2.8 when i taring to iterate pymongo object getting an error like this.
database error: Executor error: InternalError: ambiguous positional
projection
what is the reason for this error? How it solve??
If a positional operator appears in a projection or update, and there were multiple array matches against the document, MongoDB will issue an error.
so basically the issue is with the $ in the products.id.$
and this is an expected behavior. please refer https://jira.mongodb.org/browse/SERVER-14662 for more info and examples.

Mongo {$ne : null} not working as expected

When I issue the following query:
db.users.find({"pic.status" : {$ne : null} }, {"pic" : 1}).toArray()
I expect to receive all users whose pic.status is NOT null. However, the actual result looks something like this:
{
"_id" : ObjectId("4f1e1ab9cdf9dbaa160000bf"),
"pic" : {
"id" : "4f1e1ab9cdf9dbaa160000be",
"status" : null
}
},
{
"_id" : ObjectId("4f1e28480eaf38193d00006f"),
"pic" : {
"id" : "4f1e28480eaf38193d00006e",
"status" : null
}
}
That is, I receive users whose pic.status IS null. How can I fix this?
I know it's an old question, and might not be relevant anymore, but as there was no accepted answer, I thought I'll comment for anyone looking for answer.
I was able to reproduce the problem on MongoDB version 2.4.9.
> db.sourceListings.findOne({displayed:{$ne:null}});
{
<.. other stuff went here..>
"displayed" : null
}
The problem disappears on Version 2.6.1:
> db.sourceListings.findOne();
{
<.. other stuff ..>
"displayed" : null
}
> db.sourceListings.findOne({displayed:{$ne:null}});
null
Probably was fixed somewhere in between these two versions.
I cannot seem to reproduce this. What version of Mongo are you using? (I am using 2.1.1-pre) Here are the steps that I took. The following is from the JS shell:
> db.users.save({
"_id" : 1,
"pic" : {
"id" : "4f1e1ab9cdf9dbaa160000be",
"status" : null
}
});
> db.users.save({
"_id" : 2,
"pic" : {
"id" : "4f1e28480eaf38193d00006e",
"status" : null
}
});
> db.users.save({
"_id" : 3,
"pic" : {
"id" : "4f1e28480eaf38193d00006e",
"status" : "Something"
}
});
> db.users.find({"pic.status":{$ne:null}}, {pic:1}).toArray()
[
{
"_id" : 3,
"pic" : {
"id" : "4f1e28480eaf38193d00006e",
"status" : "Something"
}
}
]
Only the document containing "pic.status":"Something" is returned.
My only thought is, are you absolutely certain that the value of (null) in the query is the same as what is saved in the documents? Were the documents saved using the JS shell, or were they saved using a driver in a different language? Theoretically, null, should be null, should be null, in any language, but I know that different languages represent "no value" differently. In python, for example, the value for "no value" is (None). (null) is not recognised in python.
In a python shell, I attempted to save a document with (null) as a value, but received an error:
In [13]: coll.save({"_id":5, "pic":{"id":5, "status":null}})
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/Users/mbastien/mongodb-osx-x86_64-2.0.1/bin/<ipython-input-13-1ad232456c88> in <module>()
----> 1 coll.save({"_id":5, "pic":{"id":5, "status":null}})
NameError: name 'null' is not defined
I then inserted (with the Python shell) a status of 'null' ('null' being a string)
In [15]: coll.save({"_id":5, "pic":{"id":5, "status":'null'}})
Out[15]: 5
Not surprisingly, when I reran the query in the JS shell, this document was returned, because 'null' != null
> db.users.find({"pic.status":{$ne:null}}, {pic:1}).toArray()
[
{
"_id" : 3,
"pic" : {
"id" : "4f1e28480eaf38193d00006e",
"status" : "Something"
}
},
{
"_id" : 5,
"pic" : {
"status" : "null",
"id" : 5
}
}
]
Is this similar to what you are experiencing, or can you reproduce this 100% in the JS shell? Hopefully, we will be able to get to the root of this issue!
Use $nin with a single element in the array. It'll behave as you expect. KI with many of the people who use mongo.