How to find specific key in MongoDB? - mongodb

I have to find all the documents which include "p396:branchCode" as key in MongoDB.Value does not matter,can be anything.I tried using
{"p396:branchCode": new RegExp(".*")}
in MongoVUE but i found nothing.
My db is very nested and branchCode has superkey "p396:checkTellersEApproveStatus"

Your key is nested under a super-key, so you need to use the dot-operator:
{"p396:checkTellersEApproveStatus.p396:branchCode": {$exists: true}}
This assumes p396:branchCode is always under p396:checkTellersEApproveStatus. When that's not the case, you have a problem, because MongoDB does not allow to do queries for unknown keys. When the number of possible super-keys is low, you could query for all of them with the $or-operator. When not, then your only option is to refactor your objects to arrays. To give an example, a structure like this:
properties: {
prop1: "value1",
prop2: "value2",
prop3: "value3"
}
would be far easier to query for values under arbitrary keys when made to look like this:
properties: [
{ key: "prop1", value:"value1"} ,
{ key: "prop2", value:"value2"},
{ key: "prop3", value:"value3"}
]
because you could just do db.collection.find({"properties.value":"value2"})

If you are actually "mixing types then that probably is not a good thing. But if all you care about is that the field $exists then that is the operator to use:
db.collection.find({
"p396:checkTellersApproveStatus.p396:branchCode": { "$exists": true }
})
If the values are actuall "all" numeric and you have an expected "range" then use $gt and $lt operators instead. This allows an "index" on the field to be used. And a "sparse" index where this was not present in all documents would improve performance:
db.collection.find({
"p396:checkTellersApproveStatus.p396:branchCode": {
"$gt": 0, "$lt": 99999
}
})
In all cases, this is the "child" of the parent "p396:checkTellersApproveStatus", so you use "not notation" to acess the full path to the property.

Sounds like you want to use the $exists operator.
{'p396:branchCode': {$exists: true}}
This assumes this query is part of the path:
{ 'p396:checkTellersApproveStatus': {'p396:branchCode': {$exists: true}}}
Which can be shortened to:
{ 'p396:checkTellersApproveStatus.p396:branchCode': {$exists: true}}

Related

MongoDB: find document whose subdocument contains a given value

Given is a Document like the following
{
"type" : "sometype",
"title" : "sometitle",
"references":{
"1": "someref",
"2": "otherref",
"3": ""
}
}
How can I find all documents which have the reference someref set in the subdocument references?
A simple find({references: "someref"}) doesn't work because references is not a valid array.
Document structure is not ideal for this kind of queries but you can use aggregation with $objectToArray operator:
db.collection.aggregate([
{$addFields: {refs: {$objectToArray: "$references"}}},
{$match: {"refs.v": "someref"}},
{$project:{refs: 0}}
])
If the number of subdocument fields you are looking into is small, then you can simply filter your collection using $or
db.collection.find(
{ $or: [
{"references.1": "someref"},
{"references.2": "someref"},
{"references.3": "someref"}
]} )

Querying MongoDb's custom key & value with Index

I am trying to store key value data in MongoDb.
Key could be any string and I don't know about it anything more before storing, value could be any type (int, string, array). And I would like to have an index on such key & value.
I was looking on a (Multikey Index) over an array of my key-vals but looks like it can't cover queries over array fields.
Is it possible to have an index on a custom key & value in mongoDb and make queries with such operations as $exists and $eq and $gte, $lte, $and, $or, $in without COLLSCAN but through an IXSCAN stage?
Or maybe I need another Db for that?
I may have misunderstood your question but I think that this is precisely where MongoDB's strengths are - dealing with different shapes of documents and data types.
So let's say you have to following two documents:
db.test.insertMany([
{
key: "test",
value: [ "some array", 1 ]
},
{
key: 12.7,
values: "foo"
}
])
and you create a compound index like this:
db.test.createIndex({
"key": 1,
"value": 1
})
then the following query will use that index:
db.test.find({ "key": "test", "value": 1 })
and also more complicated queries will do the same:
db.test.find({ "key": { $exists: true }, "value": { gt: 0 } })
You can verify this by adding a .explain() to the end of the above queries.
UPDATE based on your comment:
You don't need the aggregation framework for that. You can simply do something like this:
db.test.distinct("user_id", { "key": { $exists: true } })
This query is going to use the above index. Moreover it can be made even faster by changing the index definition to include the "user_id" field like this:
db.test.createIndex({
"key" : 1.0,
"value" : 1.0,
"user_id" : 1
})
This, again, can be verified by running the following query:
db.test.explain().distinct("user_id", { "key": { $exists: true } })
If your key can be any arbitrary value, then this is impossible. Your best bet is to create an index on some other known field to limit the initial results so that the inevitable collection scan's impact is reduced to a minimum.

How to remove a key with any value in mongo collection? [duplicate]

{
name: 'book',
tags: {
words: ['abc','123'],
lat: 33,
long: 22
}
}
Suppose this is a document. How do I remove "words" completely from all the documents in this collection? I want all documents to be without "words":
{
name: 'book',
tags: {
lat: 33,
long: 22
}
}
Try this: If your collection was 'example'
db.example.update({}, {$unset: {words:1}}, false, true);
Refer this:
http://www.mongodb.org/display/DOCS/Updating#Updating-%24unset
UPDATE:
The above link no longer covers '$unset'ing. Be sure to add {multi: true} if you want to remove this field from all of the documents in the collection; otherwise, it will only remove it from the first document it finds that matches. See this for updated documentation:
https://docs.mongodb.com/manual/reference/operator/update/unset/
Example:
db.example.update({}, {$unset: {words:1}} , {multi: true});
In the beginning, I did not get why the question has a bounty (I thought that the question has a nice answer and there is nothing to add), but then I noticed that the answer which was accepted and upvoted 15 times was actually wrong!
Yes, you have to use $unset operator, but this unset is going to remove the words key which does not exist for a document for a collection. So basically it will do nothing.
So you need to tell Mongo to look in the document tags and then in the words using dot notation. So the correct query is.
db.example.update(
{},
{ $unset: {'tags.words':1}},
false, true
)
Just for the sake of completion, I will refer to another way of doing it, which is much worse, but this way you can change the field with any custom code (even based on another field from this document).
db.example.updateMany({},{"$unset":{"tags.words":1}})
We can also use this to update multiple documents.
db.collection.updateMany({}, {$unset: {"fieldName": ""}})
updateMany requires a matching condition for each document, since we are passing {} it is always true. And the second argument uses $unset operator to remove the required field in each document.
To remove or delete field in MongoDB
For single Record
db.getCollection('userData').update({}, {$unset: {pi: 1}})
For Multi Record
db.getCollection('userData').update({}, {$unset: {pi: 1}}, {multi: true})
Starting in Mongo 4.2, it's also possible to use a slightly different syntax:
// { name: "book", tags: { words: ["abc", "123"], lat: 33, long: 22 } }
db.collection.updateMany({}, [{ $unset: ["tags.words"] }])
// { name: "book", tags: { lat: 33, long: 22 } }
Since the update method can accept an aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline), it means the $unset operator used here is the aggregation one (as opposed to the "query" one), whose syntax takes an array of fields.
The solution for PyMongo (Python mongo):
db.example.update({}, {'$unset': {'tags.words':1}}, multi=True);
I was trying to do something similar to this but instead remove the column from an embedded document. It took me a while to find a solution and this was the first post I came across so I thought I would post this here for anyone else trying to do the same.
So lets say instead your data looks like this:
{
name: 'book',
tags: [
{
words: ['abc','123'],
lat: 33,
long: 22
}, {
words: ['def','456'],
lat: 44,
long: 33
}
]
}
To remove the column words from the embedded document, do this:
db.example.update(
{'tags': {'$exists': true}},
{ $unset: {'tags.$[].words': 1}},
{multi: true}
)
or using the updateMany
db.example.updateMany(
{'tags': {'$exists': true}},
{ $unset: {'tags.$[].words': 1}}
)
The $unset will only edit it if the value exists but it will not do a safe navigation (it wont check if tags exists first) so the exists is needed on the embedded document.
This uses the all positional operator ($[]) which was introduced in version 3.6
To Remove a field you can use this command(this will be applied to all the documents in the collection) :
db.getCollection('example').update({}, {$unset: {Words:1}}, {multi: true});
And to remove multiple fields in one command :
db.getCollection('example').update({}, {$unset: {Words:1 ,Sentences:1}}, {multi: true});
Because I kept finding this page when looking for a way to remove a field using MongoEngine, I guess it might be helpful to post the MongoEngine way here too:
Example.objects.all().update(unset__tags__words=1)
In mongoDB shell this code might be helpful:
db.collection.update({}, {$unset: {fieldname: ""}} )
By default, the update() method updates a single document. Set the Multi Parameter to update all documents that match the query criteria.
Changed in version 3.6.
Syntax :
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ]
}
)
Example :
db.getCollection('products').update({},{$unset: {translate:1, qordoba_translation_version:1}}, {multi: true})
In your example :
db.getCollection('products').update({},{$unset: {'tags.words' :1}}, {multi: true})
And for mongomapper,
Document: Shutoff
Field to remove: shutoff_type
Shutoff.collection.update( {}, { '$unset' => { 'shutoff_type': 1 } }, :multi => true )
It's worth mentioning, if you are using Typegoose/Mongoose your field needs to be declared in your model otherwise $unset will silently fail.
After a refactoring of a database this caught me unaware. The redundant fields were no longer in my model and I was running an $unset but nothing was happening.
So if you are doing some refactoring make sure you $unset your redundant fields before removing them from the model.
{
name: 'book',
tags: {
words: ['abc','123'],
lat: 33,
long: 22
}
}
Ans:
db.tablename.remove({'tags.words':['abc','123']})
Checking if "words" exists and then removing from the document
db.users.update({"tags.words" :{$exists: true}},
{$unset:{"tags.words":1}},false,true);
true indicates update multiple documents if matched.
you can also do this in aggregation by using project at 3.4
{$project: {"tags.words": 0} }
To reference a package and remove various "keys",
try this
db['name1.name2.name3.Properties'].remove([
{
"key" : "name_key1"
},
{
"key" : "name_key2"
},
{
"key" : "name_key3"
}
)]

How to check order of Array element in Mongodb?

In MongoDB, is there any easy way to check Order of element in Array? For example I have a document like this:
{
_id: 1,
tags: ["mongodb", "rethinkdb", "couchbase", "others"]
}
I would like to check in tags field if mongodb come before rethinkdb or not(lets see in array element, mongodb=0, rethinkdb=1 index, so mongodb come first and our case match.)?
but if there is another document (like below) where rethinkdb comes before mongodb,It case does not match.
{
_id: 2,
tags: ["rethinkdb", "mongodb", "couchbase"]
}
Here mongodb(1) comes after rethinkdb(0) so our case does not match.
Your question is not really as clear as you think it is, and thus why there are several ways to answer it:
If you are looking just to find out if a document has "mongodb" as the first element of the array then you just issue a query like this:
db.collection.find({ "tags.0": "mongodb" })
And that will return only the documents that match the given value at the specified index position using "dot notation".
If you actually expect to match if an array is in an "expected order" then you can get some help from the aggregation pipeline and set operators that are available and other features in MongoDB 2.6:
db.collection.aggregate([
{ "$project": {
"$_id": "$$ROOT",
"matched": { "$setEquals": [
"$tags",
["mongodb", "rethinkdb", "couchbase", "others"]
]}
}},
{ "$match": { "matched": true }}
])
Or if your want is to make sure that the "mongodb" value comes before the "rethinkdb" value, then you will need to evaluate in JavaScript with mapReduce, or something equally not nice like the $where operator:
db.collection.find({
"$where": function() {
return this.tags.indexOf("mongodb") < this.tags.indexOf("rethinkdb");
}
})

How to remove a field completely from a MongoDB document?

{
name: 'book',
tags: {
words: ['abc','123'],
lat: 33,
long: 22
}
}
Suppose this is a document. How do I remove "words" completely from all the documents in this collection? I want all documents to be without "words":
{
name: 'book',
tags: {
lat: 33,
long: 22
}
}
Try this: If your collection was 'example'
db.example.update({}, {$unset: {words:1}}, false, true);
Refer this:
http://www.mongodb.org/display/DOCS/Updating#Updating-%24unset
UPDATE:
The above link no longer covers '$unset'ing. Be sure to add {multi: true} if you want to remove this field from all of the documents in the collection; otherwise, it will only remove it from the first document it finds that matches. See this for updated documentation:
https://docs.mongodb.com/manual/reference/operator/update/unset/
Example:
db.example.update({}, {$unset: {words:1}} , {multi: true});
In the beginning, I did not get why the question has a bounty (I thought that the question has a nice answer and there is nothing to add), but then I noticed that the answer which was accepted and upvoted 15 times was actually wrong!
Yes, you have to use $unset operator, but this unset is going to remove the words key which does not exist for a document for a collection. So basically it will do nothing.
So you need to tell Mongo to look in the document tags and then in the words using dot notation. So the correct query is.
db.example.update(
{},
{ $unset: {'tags.words':1}},
false, true
)
Just for the sake of completion, I will refer to another way of doing it, which is much worse, but this way you can change the field with any custom code (even based on another field from this document).
db.example.updateMany({},{"$unset":{"tags.words":1}})
We can also use this to update multiple documents.
db.collection.updateMany({}, {$unset: {"fieldName": ""}})
updateMany requires a matching condition for each document, since we are passing {} it is always true. And the second argument uses $unset operator to remove the required field in each document.
To remove or delete field in MongoDB
For single Record
db.getCollection('userData').update({}, {$unset: {pi: 1}})
For Multi Record
db.getCollection('userData').update({}, {$unset: {pi: 1}}, {multi: true})
Starting in Mongo 4.2, it's also possible to use a slightly different syntax:
// { name: "book", tags: { words: ["abc", "123"], lat: 33, long: 22 } }
db.collection.updateMany({}, [{ $unset: ["tags.words"] }])
// { name: "book", tags: { lat: 33, long: 22 } }
Since the update method can accept an aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline), it means the $unset operator used here is the aggregation one (as opposed to the "query" one), whose syntax takes an array of fields.
The solution for PyMongo (Python mongo):
db.example.update({}, {'$unset': {'tags.words':1}}, multi=True);
I was trying to do something similar to this but instead remove the column from an embedded document. It took me a while to find a solution and this was the first post I came across so I thought I would post this here for anyone else trying to do the same.
So lets say instead your data looks like this:
{
name: 'book',
tags: [
{
words: ['abc','123'],
lat: 33,
long: 22
}, {
words: ['def','456'],
lat: 44,
long: 33
}
]
}
To remove the column words from the embedded document, do this:
db.example.update(
{'tags': {'$exists': true}},
{ $unset: {'tags.$[].words': 1}},
{multi: true}
)
or using the updateMany
db.example.updateMany(
{'tags': {'$exists': true}},
{ $unset: {'tags.$[].words': 1}}
)
The $unset will only edit it if the value exists but it will not do a safe navigation (it wont check if tags exists first) so the exists is needed on the embedded document.
This uses the all positional operator ($[]) which was introduced in version 3.6
To Remove a field you can use this command(this will be applied to all the documents in the collection) :
db.getCollection('example').update({}, {$unset: {Words:1}}, {multi: true});
And to remove multiple fields in one command :
db.getCollection('example').update({}, {$unset: {Words:1 ,Sentences:1}}, {multi: true});
Because I kept finding this page when looking for a way to remove a field using MongoEngine, I guess it might be helpful to post the MongoEngine way here too:
Example.objects.all().update(unset__tags__words=1)
In mongoDB shell this code might be helpful:
db.collection.update({}, {$unset: {fieldname: ""}} )
By default, the update() method updates a single document. Set the Multi Parameter to update all documents that match the query criteria.
Changed in version 3.6.
Syntax :
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ]
}
)
Example :
db.getCollection('products').update({},{$unset: {translate:1, qordoba_translation_version:1}}, {multi: true})
In your example :
db.getCollection('products').update({},{$unset: {'tags.words' :1}}, {multi: true})
And for mongomapper,
Document: Shutoff
Field to remove: shutoff_type
Shutoff.collection.update( {}, { '$unset' => { 'shutoff_type': 1 } }, :multi => true )
It's worth mentioning, if you are using Typegoose/Mongoose your field needs to be declared in your model otherwise $unset will silently fail.
After a refactoring of a database this caught me unaware. The redundant fields were no longer in my model and I was running an $unset but nothing was happening.
So if you are doing some refactoring make sure you $unset your redundant fields before removing them from the model.
{
name: 'book',
tags: {
words: ['abc','123'],
lat: 33,
long: 22
}
}
Ans:
db.tablename.remove({'tags.words':['abc','123']})
Checking if "words" exists and then removing from the document
db.users.update({"tags.words" :{$exists: true}},
{$unset:{"tags.words":1}},false,true);
true indicates update multiple documents if matched.
you can also do this in aggregation by using project at 3.4
{$project: {"tags.words": 0} }
To reference a package and remove various "keys",
try this
db['name1.name2.name3.Properties'].remove([
{
"key" : "name_key1"
},
{
"key" : "name_key2"
},
{
"key" : "name_key3"
}
)]