Searching with dynamic field name in MongoDB - mongodb

I have a situation where records in Mongo DB are like :
{
"_id" : "xxxx",
"_class" : "xxxx",
"orgId" : xxx,
"targetKeyToOrgIdMap" : {
"46784_56139542ecaa34c13ba9e314" : 46784,
"47530_562f1bc5fc1c1831d38d1900" : 47530,
"700004280_56c18369fc1cde1e2a017afc" : 700004280
},
}
I have to find out the records where child nodes of targetKeyToOrgIdMap has a particular set of values. That means, I know what the value is going to be there in the record in "46784_56139542ecaa34c13ba9e314" : 46784 part. And the field name is variable, its combination of the value and some random string.
In above example, I have 46784, and I need to find all the records which have 46784 in that respective field.
Is there any way I can fire some regex or something like that or by using any other mean where I would get the records which has the value I need in the child nodes of the field targetKeyToOrgIdMap.
Thanks in advance

You could use MongoDB's $where like this:
db.myCollection.find( { $where: function() {
for (var key in obj.targetKeyToOrgIdMap) {
if (obj.targetKeyToOrgIdMap[key] == 46784){
return true;
}
}
}}).each { obj ->
println obj
}
But be aware that this will require a full table scan where the function is executed for each document. See documentation.

Related

MongoDB Compound text search

I have a collection like this in my mongo database, let's say it's called taxonomic.
{
"_id" : ObjectId("5810e15a762a39b41912a131"),
"validName" : "Eros",
"idUser" : ObjectId("1")
}
{
"_id" : ObjectId("5810e15a762a39b41912a132"),
"validName" : "Eros",
"idUser" : ObjectId("2")
}
I've already created a compound index to be able to search for the two values I want, such as this.
db.taxonomic.createIndex({"idUser":1,"validName":1})
Now, I want to be able to search and get a return from it only when both of the parameters are found on the same document of the collections, here's my try:
db.taxonomic.find({$text:{$search:"Eros 2"}},{idUser:1,validName:1})
The problem with this method is that it will return any match of "Eros" OR "2", what I want is a return of the values when "Eros" AND "2" are matched in a document of the collection.
Thank you for any help!
I dont think you require a text Index for it if you only want specific string
db.taxonomic.find({"$or" : [{"validName" : "Eros"},{"validName" : "2"}]},{idUser:1,validName:1})

How to get multiple document using array of MongoDb id?

I have an array of ids and I want to get all document of them at once. For that I am writing but it return 0 records.
How can I search using multiple Ids ?
db.getCollection('feed').find({"_id" : { "$in" : [
"55880c251df42d0466919268","55bf528e69b70ae79be35006" ]}})
I am able to get records by passing single id like
db.getCollection('feed').find({"_id":ObjectId("55880c251df42d0466919268")})
MongoDB is type sensitive, which means 1 is different with '1', so are "55880c251df42d0466919268" and ObjectId("55880c251df42d0466919268"). The later one is in ObjectID type but not str, and also is the default _id type of MongoDB document.
You can find more information about ObjectID here.
Just try:
db.getCollection('feed').find({"_id" : {"$in" : [ObjectId("55880c251df42d0466919268"), ObjectId("55bf528e69b70ae79be35006")]}});
I believe you are missing the ObjectId. Try this:
db.feed.find({
_id: {
$in: [ObjectId("55880c251df42d0466919268"), ObjectId("55bf528e69b70ae79be35006")]
}
});
For finding records of multiple documents you have to use "$in" operator
Although your query is fine, you just need to add ObjectId while finding data for Ids
db.feed.find({
"_id" : {
"$in" :
[ObjectId("55880c251df42d0466919268"),
ObjectId("55bf528e69b70ae79be35006")
]
}
});
Just I have use it, and is working fine:
module.exports.obtenerIncidencias386RangoDias = function (empresas, callback) {
let arraySuc_Ids = empresas.map((empresa)=>empresa.sucursal_id)
incidenciasModel.find({'sucursal_id':{$in:arraySuc_Ids}
}).sort({created_at: 'desc'}).then(
(resp)=> {
callback(resp)}
)
};
where:
empresas = ["5ccc642f9e789820146e9cb0","5ccc642f9e789820146e9bb9"]
The Id's need to be in this format : ObjectId("id").
you can use this to transform your string ID's :
const ObjectId = require('mongodb').ObjectId;
store array list in var and pass that array list to find function
var list=db.collection_name.find()
db.collection_name.find({_id:{$in:list}})
db.getCollection({your_collection_name}).find({
"_id" : {
"$in" :
[({value1}),
({value2})
]
}
})

MongoDB - update a field inside a map entry

We have a mongodb document with the following structure: One of the document's fields is a map, and each map entry has several fields of it's own.
We want a way to update the value of one field inside a specific map entry using mogodb update query.
To clarify things, if we have the document as bellow, we want to update "callBackUrl" for entry 1 in the map "urlSettings" to "yadayada.com".
Is that possible at all?
SystemSettings : {
urlSettings : {
1 : {
callBackUrl : "blabla.com",
(more fields...)
},
2 : {
...
},
...
},
...
}
check the below query :
db.collection.update(
{"SystemSettings.urlSettings.1.callBackUrl" : "blabla.com"},
{"$set":{"SystemSettings.urlSettings.1.callBackUrl" : "yadayada.com"}}
);

Override existing Docs in production MongoDB

I have recently changed one of my fields from object to array of objects.
In my production I have only 14 documents with this field, so I decided to change those fields.
Is there any best practices to do that?
As it is in my production I need to do it in a best way possible?
I got the document Id's of those collections.like ['xxx','yyy','zzz',...........]
my doc structure is like
_id:"xxx",option1:{"op1":"value1","op2":"value2"},option2:"some value"
and I want to change it like(converting object to array of objects)
_id:"xxx",option1:[{"op1":"value1","op2":"value2"},
{"op1":"value1","op2":"value2"}
],option2:"some value"
Can I use upsert? If so How to do it?
Since you need to create the new value of the field based on the old value, you should retrieve each document with a query like
db.collection.find({ "_id" : { "in" : [<array of _id's>] } })
then iterate over the results and $set the value of the field to its new value:
db.collection.find({ "_id" : { "in" : [<array of _id's>] } }).forEach(function(doc) {
oldVal = doc.option1
newVal = compute_newVal_from_oldVal(oldVal)
db.collection.update({ "_id" : doc._id }, { "$set" : { "option" : newVal } })
})
The document structure is rather schematic, so I omitted putting in actual code to create newVal from oldVal.
Since it is an embedded document type you could use push query
db.collectionname.update({_id:"xxx"},{$push:{option1:{"op1":"value1","op2":"value2"}}})
This will create document inside embedded document.Hope it helps

How to query a relative element using MongoDB

I have a document like this:
{
"whoKnows" : {
"name" : "Jeff",
"phone" : "123-123-1234"
},
"anotherElement" : {
"name" : "Jeff",
"phone" : "321-321-3211"
}
}
How can any instance of "name" by queried? For example, using a wildcard may look something like,
db.collection.find( { "*.name" : "Jeff" } )
Or if regex was support in the element place, it might look like,
db.collection.find( { /.*\.name/ : "Jeff" } )
Is it possible to accomplish this using MongoDB?
Side note: I'm not looking for a solution like,
db.collection.find({
"$or": [
{ "whoKnows.name" : "Jeff" },
{ "anotherElement.name" : "Jeff" }
]
})
I need a truly relative path solution as I do not know what the parent element will be (unless there is a way to generate the name of every element - then I could dynamically generate the $or clause at runtime).
Everything about this is fairly horrible, you cannot possibly index on something like the "name" values and your "path" to each attribute is going to vary everywhere. So this is really bad for queries.
I notice you mention "nested" structures, and you still could accommodate this with a similar proposal and some additional tagging, but I want you to consider this "phone book" type example:
{
"phones": [
{
"type": "Home",
"name" : "Jeff",
"phone" : "123-123-1234"
},
{
"type": "Work",
"name" : "Jeff",
"phone" : "123-123-1234"
},
]
}
Since this is actually sub-documents within an array, fields like "name" always share the same path, so not only can you index these (which is going to be good for performance) but the query is very basic:
db.collection({ "phones.name": "Jeff" })
That does exactly what you need by finding "Jeff" in any "name" entry. If you need a hierachy, then add some fields in those sub-documents to indicate the parent/child relationship that you can use in post processing. Or even as a materialized path which could aid your queries.
It really is the better approach.
If you really must keep this kind of structure then at least do something like this with the JavaScript that will bail out on the first match at depth:
db.collection.find(
function () {
var found = false;
var finder = function( obj, field, value ) {
if ( obj.hasOwnProperty(field) && obj[field] == value )
found = true;
if (found) return true;
for( var n in obj ) {
if ( Object.prototype.toString.call(obj[n]) === "[object Object]" ) {
finder( obj[n], field, value );
if (found) return true;
}
}
};
finder( this, "name", "Jeff" );
return found;
}
)
The format there is shorthand notation for the $where operator, which is pretty bad news for performance, but your structure isn't offering much other choice. At any rate, the function should recurse into each nested document until the "field" with the "value" is found.
For anything of production scale, really look at changing the structure to something that can be indexed and accessed quickly. The first example should give you a starting point. Relying on arbitrary JavaScript for queries as your present structure constrains you to is bad news.
If these are similar instance, what stops you in putting these in an array? That would be easier to query.
In it's current form this looks as good as writing your own $where condition to parse all document structure and is not an efficient operation!
Although highly inefficient and I wouldn't suggest using this in a production environment, following is one of the simplest way (with its own various catches) you can query:
db.query.find({$where: function() { x = tojsononeline(this); return x.indexOf('"name" : "Jeff",') >= 0; } })
Please note that this will cause a tablescan and if you have a pre-condition you may want to specify that before the where clause in the query.