How can I present fields with similar name on mongo shell? - mongodb

I have a collection name 'persons'. Inside the collection, I have the following structure. I would like to get to present all the fields that contain the term "friend".
name: 'David',
contacts: {
friend_1: 'Bill'
friend_2: 'George'
friend_3: 'Donald'
friend_4: 'Richard'
managaer: 'James'
mentor: 'Andy'
}
I thought to try maybe db.persons.find({}, {/.*friend.*/: 1}), but obviously it didn't work.
How can I achieve it?

It doesn't seem to be a correct structure. If this is the case, maybe you can store an array in 'friends' field.
name: 'David',
contacts: {
friends: ['Bill', 'George', 'Donald', 'Richard'],
manager: 'James',
mentor: 'Andy'
}

First of all, obviously this is not the best structure, but is what it is, and then you can use this aggregation query:
First set the object as array with $objectToArray to filter by the regex.
Then use $filter with $regexMatch to get only values you want into the array.
And recreate the object again using $arrayToObject.
db.collection.aggregate([
{
"$set": {
"contacts": {
"$objectToArray": "$contacts"
}
}
},
{
"$project": {
"name": 1,
"contacts": {
"$filter": {
"input": "$contacts",
"as": "c",
"cond": {
"$regexMatch": {
"input": "$$c.k",
"regex": ".*friend.*",
"options": "i"
}
}
}
}
}
},
{
"$set": {
"contacts": {
"$arrayToObject": "$contacts"
}
}
}
])
Example here

Related

how to query through hashmap data using mongo terminal

I have data stored in following format in mongodb .. help me in knowing how can I write a query to find if the database has a particular id stored in one of the sheet or not
the structure of data is like the following :-
{
"name": "abc",
"linked_data": {
"sheet 1": [
"7d387e05d3f8180a",
"8534sfjog904395"
],
"sheet 2": [
"7d387e05d3f8180a",
"54647sgdsevey67r34"
]
}
}
for example if id "8534sfjog904395" is mapped with "sheet 1".. then it should return me this data where id is mapped with the sheet.
I am passing id in the query and want to find inside linked_data and then all the sheets
Using dynamic value as field name is considered as an anti-pattern and introduce unnecessary complexity to queries. Nevertheless, you can use $objectToArray to convert the linked_data into array of k-v tuples. $filter to get only the sheet you want. Finally, revert back to original structure using $arrayToObject
db.collection.aggregate([
{
"$set": {
"linked_data": {
"$objectToArray": "$linked_data"
}
}
},
{
$set: {
linked_data: {
"$filter": {
"input": "$linked_data",
"as": "ld",
"cond": {
"$in": [
"8534sfjog904395",
"$$ld.v"
]
}
}
}
}
},
{
"$set": {
"linked_data": {
"$arrayToObject": "$linked_data"
}
}
},
{
$match: {
linked_data: {
$ne: {}
}
}
}
])
Mongo Playground

A MongoDB update query to update array values to their lowercase value

I have a Mongo collection of states, where each state contains an array of cities:
{
"_id":"636d1137cf1e57408486f795",
"state":"new york",
"cities":[
{
"cityid":"62bd8fa5396ba8aef4ad1041",
"name":"Yonkers"
},
{
"cityid":"62bd8fa5396ba8aef4ad1043",
"name":"Syracuse"
}
]
}
I need an update query that will lowercase every cities.name in the collection.
I can do an update with a literal value e.g.
db.states.updateMany(
{},
{ $set: { "cities.$[].name" : "some_value" } }
)
... , but I need the value to be based on the existing value. The closest I can get is something like this (but that doesn't work -- FieldPath field names may not start with '$')
db.states.updateMany(
{},
{ $set: { "cities.$[].name" : { $toLower: "cities.$[].name"} } }
)
You can chain up $map and $mergeObjects to perform the update. Put it in an aggregation pipeline in update.
db.collection.update({},
[
{
$set: {
cities: {
"$map": {
"input": "$cities",
"as": "c",
"in": {
"$mergeObjects": [
"$$c",
{
"name": {
"$toLower": "$$c.name"
}
}
]
}
}
}
}
}
])
Mongo Playground

MongoDB filter and get count of all nested values

I have a MongoDB collection with a schema like this:
{
"_id":"0e5101cb8c39356305830f36",
"person1":{
"name":"Test",
"status":"valid"
},
"person2":{
"name":"Test2",
"status":"invalid"
},
"person3":{
"name":"Test3",
"status":"valid"
}
}
The status field can be either valid, invalid or pending. I want to query this collection and then count, for the whole collection, how many valid, invalid and pending persons it has. I am using a no-code tool to run a query so I think I need to use something like Aggregation Framework to process this. I am new to Aggregation framework, I tried a bunch of stages but couldn't make this work. Any help is appreciated.
The data model is awkward (the first two stages below are just to get the data in a "reasonable" format), but here's one way you could do it.
db.collection.aggregate([
{
"$project": {
"rootArray": {"$objectToArray": "$$ROOT"}
}
},
{
"$project": {
"persons": {
"$map": {
"input": {
"$filter": {
"input": "$rootArray",
"cond": {
"$regexMatch": {
"input": "$$this.k",
"regex": "person"
}
}
}
},
"as": "person",
"in": "$$person.v"
}
}
}
},
{"$unwind": "$persons"},
{
"$group": {
"_id": "$persons.status",
"count": {"$count": {} }
}
}
])
Try it on mongoplayground.net.

Mongo Project _id of Array of Documents

I struggle writing Mongo Queries. I can never understand why it doesn't return what I expect and yes I am reading the documentation but apparently to dumb to understand.
In Compass I write this query for a State collection with a document array of cities.
{"Cities.CityName":"Denver"}
This returns to me the State of Colorado document with ALL the cities in the document array. My sample below just shows one city document but they are all there.
{
"_id": {"$oid":"6146ada531696ee91a3f9fa4"},
"StateName": "Colorado",
"StateCode": "CO",
"Cities": [{
"_id": {"$oid":"6146ada531696ee91a3f5a50"},
"CityName": "Denver",
"Latitude": "39.55666000",
"Longitude": "-104.89609000"
}...]
}
OK so I'm thinking clearly we matched on the CityName now just project the _id of the City document.
{"Cities._id":1}
But this always returns to me the State document id NOT the matched City Document _id.
What am I doing wrong?
1) You can use $ (projection) or $elemMatch (projection):
use case: The positional $ operator limits the contents of an <array> to return the first element that matches the query condition on the array.
ex:
{ "Cities.$": 1 } or ​{"Cities": { "$elemMatch": { "CityName": "Denver" } } }
result:
{
​"_id":{"$oid":"6146ada531696ee91a3f9fa4"},
​"Cities":[{
​"_id":{"$oid":"6146ada531696ee91a3f5a50"},
​"CityName":"Denver",
​"Latitude":"39.55666000",
​"Longitude":"-104.89609000"
​}]
}
Playground
Note: You have to specify the required result fields in the projection!
2) You can use $filter aggregation operator, supported from MongoDB 4.4 in find() method:
use case: Selects a subset of an array to return based on the specified condition. Returns an array with only those elements that match the condition. The returned elements are in the original order.
ex:
{
"Cities": {
"$filter": {
"input": "$Cities",
"cond": { "$eq": ["$$this.CityName", "Denver"] }
}
}
}
result:
{
​"_id":{"$oid":"6146ada531696ee91a3f9fa4"},
​"Cities":[{
​"_id":{"$oid":"6146ada531696ee91a3f5a50"},
​"CityName":"Denver",
​"Latitude":"39.55666000",
​"Longitude":"-104.89609000"
​}...{}]
}
Playground
Note: You have to specify the required result fields in the projection!
2.1) You can use $map aggregation operator to select only _ids from the Cities array:
use case: Applies an expression to each item in an array and returns an array with the applied results.
ex:
{
"Cities": {
"$map": {
"input": {
"$filter": {
"input": "$Cities",
"cond": { "$eq": ["$$this.CityName", "Denver"] }
}
},
"in": "$$this._id"
}
}
}
result:
{
"_id":{"$oid":"6146ada531696ee91a3f9fa4"},
"Cities":[
{"$oid":"6146ada531696ee91a3f5a50"},
{"$oid":"6146ada531696ee91a3f5a51"},
....
]
}
Playground
Note: You have to specify the required result fields in the projection!
3) You can use aggregation method aggregate() for more customization:
- ex:
$match to check query condition
$addFields to add or format the existing properties
$filter and $map i have explained in 2) point
db.collection.aggregate([
{ "$match": { "Cities.CityName": "Denver" } },
{
"$addFields": {
"Cities": {
"$map": {
"input": {
"$filter": {
"input": "$Cities",
"cond": { "$eq": ["$$this.CityName", "Denver"] }
}
},
"in": "$$this._id"
}
}
}
}
])
Playground
result:
[
{
"Cities": [
ObjectId("6146ada531696ee91a3f5a50")
],
"StateCode": "CO",
"StateName": "Colorado",
"_id": ObjectId("6146ada531696ee91a3f9fa4")
}
]

Return array of fields from subdocument

can anyone please help I want to query mongo to unwind the array,and i am using mongdb native driver My collection document is as follow,Also please ignore my objectId its just for sample
{
"_id":ObjectId(123),
"name":"Sam",
"age":20,
"hobbiesDetail":[
{
"description":"FootBall",
"level":"20%"
},
{
"description":"Cricket",
"level":"80%"
}
]
},
{
"_id":ObjectId(124),
"name":"Ted",
"age":26,
"hobbiesDetail":[
{
"description":"FootBall",
"level":"20%"
}
]
}
And my expected output is
[
{
"name":"Sam",
"age":20,
"hobbies":"Football,Cricket"
},
{
"name":"Ted",
"age":26,
"hobbies":"Football"
}
]
I just want to unwind my array and add a comma between hobbies description in one query, Thanx for any help
All you need is a $projection with the $map array operator.
db.collection.aggregate([
{ "$project": {
"name": 1,
"age": 1,
"hobbies": {
"$map": {
"input": "$hobbiesDetail",
"as": "hobby",
"in": "$$hobby.description"
}
}
}}
])