Mongodb: Query a json-object nested in an array - arrays

I'm quite new to mongodb and there is one thing I can't solve right now:
Let's pretend, you have the following document (simplified):
{
'someKey': 'someValue',
'array' : [
{'name' : 'test1',
'value': 'value1'
},
{'name' : 'test2',
'value': 'value2'
}
]
}
Which query would return the json-object, in which the value equals 'value2'?
That means, i need this json-object:
{
'name' : 'test2',
'value': 'value2'
}
Of course I already tried a lot of possible queries, but none of them returned the right, e.g.
db.test.find({'array.value':'value2'})
db.test.find({'array.value':'value2'}, {'array.value':1})
db.test.find({'array.value':'value2'}, {'array.value':'value2'})
Can someone help and show me, what I'm doing wrong?
Thanks!

Using Positional operator
db.test.find(
{ "array.value": "value2" },
{ "array.$": 1, _id : 0 }
)
Output
{ "array" : [ { "name" : "test2", "value" : "value2" } ] }
Using aggregation
db.test.aggregate([
{ $unwind : "$array"},
{ $match : {"array.value" : "value2"}},
{ $project : { _id : 0, array : 1}}
])
output
{ "array" : { "name" : "test2", "value" : "value2" } }
Using Java Driver
MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017));
DB db = mongoClient.getDB("mydb");
DBCollection collection = db.getCollection("test");
DBObject unwind = new BasicDBObject("$unwind", "$array");
DBObject match = new BasicDBObject("$match", new BasicDBObject(
"array.value", "value2"));
DBObject project = new BasicDBObject("$project", new BasicDBObject(
"_id", 0).append("array", 1));
List<DBObject> pipeline = Arrays.asList(unwind, match, project);
AggregationOutput output = collection.aggregate(pipeline);
Iterable<DBObject> results = output.results();
for (DBObject result : results) {
System.out.println(result.get("array"));
}
output
{ "name" : "test2" , "value" : "value2"}

Try the $in operator like this:
db.test.find({"array.value" : { $in : ["value2"]}})

You can pass multiple find objects in element match for getting the exact answer.
db.test.find({'array':{$elemMatch:{value:"value2"}})
output: {'name' : 'test1','value': 'value1'}

Use $elemMatch and dot(.) to get your required output
db.getCollection('mobiledashboards').find({"_id": ObjectId("58c7da2adaa8d031ea699fff") },{ viewData: { $elemMatch : { "widgetData.widget.title" : "England" }}})

Related

MongoDB Aggregate search with comma separated string list in array

I have a MongoDB question. I have a search in an aggregation with $match.
Search should check an array if one of the values matches a value of the array inside the documents.
As an example:
var stringList = 'general,online,offline'; //--> should check each value of this list
and two documents as an example
{
"_id" : ObjectId("5e8f3a64ec717a0013d2f1f9"),
"category" : [
"general",
"online",
"internal",
"miscellaneous"
]},
{
"_id" : ObjectId("5e8f3afeec717a0013d2f1fa"),
"category" : [
"offline"
]
}
I´ve tried a lot but I don´t found out how it is possible to check each value of the string list with each value in the category array. My example should show both documents, but if I use $in I don´t get any result.
What I tried is:
Split the list by comma and map
use of $elemMatch
use if $in
use combination of $elemMatch and $in
I hope I could explain my problem with my aggregation.
Thx everyone for his help.
You should be able to split the string on , with .split function, then pass this in to a $in query.
var stringList = 'general,online,offline';
db.documents.find( { "category" : { $in : stringList.split(",") } } );
{ "_id" : ObjectId("5e8f3a64ec717a0013d2f1f9"), "category" : [ "general", "online", "internal", "miscellaneous" ] }
{ "_id" : ObjectId("5e8f3afeec717a0013d2f1fa"), "category" : [ "offline" ] }
You can also do this in a $match in an aggregation query.
> db.documents.aggregate([
{ $match : { category: { $in : stringList.split(",") } }}
])
Here is an example, where we can search the array name from by using the regex method in the query.
var x = ["sai","test","jacob","justin"],
regex = x.join("|");
db.documents.find({
"firstName": {
"$regex": regex,
"$options": "i"
}
});

Rename a sub-document field within an Array of an Document

I am trying to rename the particular child field inside an array of an collection in MONGODB
{
"_id" : Id("248NSAJKH258"),
"isGoogled" : true,
"toCrawled" : true,
"result" : [
{
"resultsId" : 1,
"title" : "Text Data to be writen",
"googleRanking" : 1,
"isrelated" : false
},
{
"resultId" : 2,
"title" : "Text Data",
"googleRanking" : 2,
"isrelated" : true
}]
**I need to rename "isrelated" to "related" ** from the collection document
Using mongo Version 4.0
I Tried :
db.collection_name.update({}, { $rename: { 'result.isrelated': 'result.related'} } )
But it didn't worked in my case
As mentioned in official documentation $rename not working for arrays.
Please check link below:
https://docs.mongodb.com/manual/reference/operator/update/rename/
But you can do something like this
let newResult = [];
db.aa1.find({}).forEach(doc => {
for (let i in doc.result) {
newResult.push({
"resultsId" : doc.result[i]['resultsId'],
"title" : doc.result[i]['title'],
"googleRanking" : doc.result[i]['googleRanking'],
"related" : doc.result[i]['isrelated'],
})
}
db.aa1.updateOne({_id: doc._id}, {$set: {result: newResult}});
newResult = []
})

Mongodb query array

I need to get all documents that match an array of objects or an object with many fields.
Example 1 (array of objects)
If the document match the country_code than he must have one of postal_codes too
var locations = [
{
country_code : 'IT',
postal_codes : [21052, 21053, 21054, 21055]
},
{
country_code : 'GER',
postal_codes : [41052, 41053, 41054, 41055]
}
]
Example 2 (object with fields)
If the document match the key than it must have one of the values of that key
var location = {
'IT' : [21052, 21053, 21054, 21055],
'GER' : [41052, 41053, 41054, 41055]
}
I like the first type of document to match(array of objects) but how can i use to get all documents that match?
The documents to find have this structure:
{
"_id" : ObjectId("587f6f57ed6b9df409db7370"),
"description" : "Test description",
"address" : {
"postal_code" : "21052",
"country_code" : "IT"
}
}
You can use $in to find such collections.
db.collection_name.find(
{ address.postal_code: { $in: [your values] } },
)
Check this link for querying child objects.
Check this link for mongoDB $in
One way is to use the $or operator. This will help you limit the combinations of country_code and postal_code.
Your query should look something like this.
db.locations.find({
$or: [{
"country_code": "IT",
"postal_code": {
$in: [21052, 21053, 21054, 21055]
}
}, {
"country_code": "GER",
"postal_code": {
$in: [41052, 41053, 41054, 41055]
}
}]
})

How to query a single embedded document in an array in MongoDB?

I am trying to query a single embedded document in an array in MongoDB. I don't know what I am doing wrong. Programmatically, I will query this document and insert new embedded documents into the currently empty trips arrays.
{
"_id" : ObjectId("564b3300953d9d51429163c3"),
"agency_key" : "DDOT",
"routes" : [
{
"route_id" : "6165",
"route_type" : "3",
"trips" : [ ]
},
{
"route_id" : "6170",
"route_type" : "3",
"trips" : [ ]
},
...
]
}
Following queries -I run in mongo shell- return empty:
db.tm_routes.find( { routes : {$elemMatch: { route_id:6165 } } } ).pretty();
db.tm_routes.find( { routes : {$elemMatch: { route_id:6165,route_type:3 } } } ).pretty();
db.tm_routes.find({'routes.route_id':6165}).pretty()
also db.tm_routes.find({'routes.route_id':6165}).count() is 0.
The following query returns every document in the array
db.tm_routes.find({'routes.route_id':'6165'}).pretty();
{
"_id" : ObjectId("564b3300953d9d51429163c3"),
"agency_key" : "DDOT",
"routes" : [
{
"route_id" : "6165",
"route_type" : "3",
"trips" : [ ]
},
{
"route_id" : "6170",
"route_type" : "3",
"trips" : [ ]
},
...
]}
but db.tm_routes.find({'routes.route_id':'6165'}).count() returns 1.
And finally, here is how I inserted data in the first place -in Node.JS-:
async.waterfall([
...
//RETRIEVE ALL ROUTEIDS FOR EVERY AGENCY
function(agencyKeys, callback) {
var routeIds = [];
var routesArr = [];
var routes = db.collection('routes');
//CALL GETROUTES FUNCTION FOR EVERY AGENCY
async.map(agencyKeys, getRoutes, function(err, results){
if (err) throw err;
else {
callback(null, results);
}
});
//GET ROUTE IDS
function getRoutes(agencyKey, callback){
var cursor = routes.find({agency_key:agencyKey});
cursor.toArray(function(err, docs){
if(err) throw err;
for(i in docs){
routeIds.push(docs[i].route_id);
var routeObj = {
route_id:docs[i].route_id,
route_type:docs[i].route_type,
trips:[]
};
routesArr.push(routeObj);
/* I TRIED 3 DIFFERENT WAYS TO PUSH DATA
//1->
collection.update({agency_key:agencyKey}, {$push:{"routes":{
'route_id':docs[i].route_id,
'route_type':docs[i].route_type,
'trips':[]
}}});
//2->
collection.update({agency_key:agencyKey}, {$push:{"routes":routeObj}});
*/
}
// 3->
collection.update({agency_key:agencyKey}, {$push:{routes:{$each:routesArr}}});
callback(null, routeIds);
});
};
},
...
var collection = newCollection(db, 'tm_routes',[]);
function newCollection(db, name, options){
var collection = db.collection(name);
if (collection){
collection.drop();
}
db.createCollection(name, options);
return db.collection(name);
}
Note: I am not using Mongoose and don't want to use if possible.
Melis,
I see what you are asking for, and what you need is help understanding how things are stored in mongodb. Things to understand:
A document is the basic unit of data for MongoDB and can be roughly compared to a row in a relational database.
A collection can be thought of as a table with a dynamic schema
So documents are stored in collections.Every document has a special _id, that is unique within a collection. What you showed us above in the following format is One document.
{
"_id" : ObjectId("564b3300953d9d51429163c3"),
"agency_key" : "DDOT",
"routes" : [
{
"route_id" : "6165",
"route_type" : "3",
"trips" : [ ]
},
{
"route_id" : "6170",
"route_type" : "3",
"trips" : [ ]
},
...
]}
If you run a query in your tm_routes collection. The find() will return each document in the collection that matches that query. Therefore when you run the query db.tm_routes.find({'routes.route_id':'6165'}).pretty(); it is returning the entire document that matches the query. Therefore this statement is wrong:
The following query returns every document in the array
If you need to find a specific route in that document, and only return that route, depending on your use, because its an array, you may have to use the $-Positional Operator or the aggregation framework.
For Node and Mongodb users using Mongoose, this is one of the ways to write the query to the above problem:
db.tm_routes.updateOne(
{
routes: {
$elemMatch: {
route_id: 6165 (or if its in a route path then **6165** could be replaced by **req.params.routeid**
}
}
},
{
$push: {
"routes.$.trips":{
//the content you want to push into the trips array goes here
}
}
}
)

MongoDB search using $in array not working

I'm using MongoDB shell version: 2.4.8, and would simply like to know why a nested array search doesn't work quite as expected.
Assume we have 2 document collections, (a) Users:
{
"_id" : ObjectId("u1"),
"username" : "user1",
"org_ids" : [
ObjectId("o1"),
ObjectId("o2")
]
}
{
"_id" : ObjectId("u2"),
"username" : "user2",
"org_ids" : [
ObjectId("o1")
]
}
and (b) Organisations:
{
"_id" : ObjectId("o1"),
"name" : "Org 1"
}
{
"_id" : "ObjectId("o2"),
"name" : "Org 2"
}
Collections have indexes defined for
Users._id, Users.org_id, Organisations._id
I would like to find all Organisations a specific user is a member of.
I've tried this:
> myUser = db.Users.find( { _id: ObjectId("u1") })
> db.Organisations.find( { _id : { $in : [myUser.org_ids] }})
yet it yields nothing as a result. I've also tried this:
> myUser = db.Users.find( { _id: ObjectId("u1") })
> db.Organisations.find( { _id : { $in : myUser.org_ids }})
but it outputs the error:
error: { "$err" : "invalid query", "code" : 12580 }
(which basically says you need to pass $in an array) ... but that's what I thought I was doing originally ? baffled.
Any ideas what I'm doing wrong?
db.collection.find() returns a cursor - according to documentation. Then myUser.org_ids is undefined, but $in field must be an array. Let's see the solution!
_id is unique in a collection. So you can do findOne:
myUser = db.Users.findOne( { _id: ObjectId("u1") })
db.Organisations.find( { _id : { $in : myUser.org_ids }})
If you are searching for a non-unique field you can use toArray:
myUsers = db.Users.find( { username: /^user/ }).toArray()
Then myUsers will be an array of objects matching to the query.

Resources