Get index of an element mongodb aggregation - arrays

Here is my collection
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"name" : "Sherlock",
"mobile" : "999999",
"adress" : [
{
"street" : "221b baker street",
"city" : "london"
},
{
"street" : "ben street",
"city" : "london"
}
],
"tags" : [
"Detective",
"Magician",
"Avenger"
]
}
Now I want to get the first or second value inside address array.
for that I'm using this command.
> db.agents.findOne({"name" : "Sherlock"},{"adress" : 1})
but instead of giving a single result it is giving the entire array like
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"adress" : [
{
"street" : "221b baker street",
"city" : "london"
},
{
"street" : "ben street",
"city" : "london"
}
]
}
It can be done by comparing array value like
db.agents.find({"adress.street": "ben street"}, {_id: 0, 'adress.$': 1});
But I don't want to compare just to print the array indexes. How can I get the single result?
Any help is appreciated..

You can use $arrayElemAt to get the specific element from the array
db.collection.aggregate([
{ $addFields: { "$arrayElemAt": ["$adress", 0] }} //index
])
and if you want to get the sliced element then you can use $slice projection
db.collection.find({}, { adress: { $slice: [2, 1] }}) // 2 index and 1 number of element

You can $unwind with includeArrayIndex to get the index of address array
db.t11.aggregate([
{$match : {"adress.street" : "ben street"}},
{$unwind : {path : "$adress", includeArrayIndex : "idx"}},
{$match : {"adress.street" : "ben street"}}
]).pretty()
you can add $project to filter the fields not required
result
> db.t11.aggregate([{$match : {"adress.street" : "ben street"}},{$unwind : {path : "$adress", includeArrayIndex : "idx"}},{$match : {"adress.street" : "ben street"}}]).pretty()
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"name" : "Sherlock",
"mobile" : "999999",
"adress" : {
"street" : "ben street",
"city" : "london"
},
"tags" : [
"Detective",
"Magician",
"Avenger"
],
"idx" : NumberLong(1)
}
>

Related

MongoDB Transform element fields into array of values only

I need help with following thing in MongoDB, what I'm trying to do is to get only marks in reviews into it's own array of values only.
Code i got so far:
db.lodging.aggregate([
{$project:{
reviews:"$host.reviews",host:"$host"
}
},
{$unwind: "$reviews"},
])
JSON Example:
"host" : {
"name" : "Grimes",
"surname" : "Terrell",
"gender" : "male",
"age" : NumberInt(55),
"picture" : "https://api.adorable.io/avatars/285/GrimesTerrell.png",
"reviews" : [
{
"reviewer" : "Mae Ryan",
"date" : "2015-06-01T02:41:46 -02:00",
"helpful" : NumberInt(8),
"kind" : NumberInt(1),
"responsive" : NumberInt(5)
},
{
"reviewer" : "Nixon Johnson",
"date" : "2016-02-08T10:35:12 -01:00",
"helpful" : NumberInt(1),
"kind" : NumberInt(1),
"responsive" : NumberInt(9)
},
]
}
This is what im trying to achieve:
{
"host" : {
"name" : "Grimes",
"surname" : "Terrell",
"gender" : "male",
"age" : NumberInt(55),
"picture" : "https://api.adorable.io/avatars/285/GrimesTerrell.png",
"reviews" : [
{
"marks" : [8,1,5],
},
{
"marks" : [1,1,9],
},
]
}
Assuming your marks' field names are always helpful, kind, responsive, you can use $map.
Here is a mongo playground for you reference

How to modify fields in specific sub-documents in an array?

I have a collection where each document has an array of sub-documents, containing several fields. I need to update specific sub-documents based on their fields, but every attempt I've done so far changes the field in all of the arrayed sub-documents
Here is some sample data:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000039"
}
]
}
When I try to use update() with the following query, it updates the ProductType on all array items, not just the one I'm trying to change.
To clarify, I want to change the array item with ItemIdLegacy: "ca-000038" to have ProductType: 20. All other Array items should remain unchanged. Query that I have tried:
db.Collection.update({"Items.ItemIdLegacy" : "ca-000038"},[{$set: { "Items.ProductType" : "20"} }],{multi: false});
This is the desired output:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000039"
}
]
}
But this is the actual output of running that query:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000039"
}
]
}
I feel like I'm missing something simple...
EDIT: I have q uery that will allow me to update a single matching element in the array, but I have thousands that would need to be done so one offs don't necessarily work (sure I could parse them all out and spam them to the shell, but I want something more elegant)
Single Element Update:
db.Collection.updateOne({"Items.ItemIdLegacy" : "ca-000038"},{ $set: { "Items.$.ProductType" : "20" } } );
Try this :-
db.collection.update({
"Items.ItemIdLegacy": "ca-000038"
},
{
$set: {
"Items.$.ProductType": 20
}
},
{
multi: true
})
Here is Working Example

$split fractions (Ranks like 5/8 to array : [5,8]) in an array of numbers during mongodb aggregation

Here is my data. I want to apply some aggregation on Rank field where rank of my record has been mentioned (for 1st record Rank: 5/8 which mean 5th out of 8).
I want to split add another field with title position and add value based on the Rank value. 1st, 2nd, third, third last, 2nd last, last and remaining all as "Other position".
For Which I am applying $split function but it is splitting this into array of string like array: ["5","8"] and i am unable to perform $subtract function due to its type string i need it in numbers array like array: [5,8].
{
"_id" : ObjectId("5a44a18c7d7aab074482e11b"),
"Rank" : "5/8",
"Status" : "Ok",
"position_temp" : [
"5",
"8"
]
}
{
"_id" : ObjectId("5a44a18c7d7aab074482e11c"),
"Rank" : "4/12",
"Status" : "Ok",
"position_temp" : [
"4",
"12"
]
}
{
"_id" : ObjectId("5a44a18c7d7aab074482e11d"),
"Rank" : "1/1",
"Status" : "Ok",
"position_temp" : [
"1",
"1"
]
}
{
"_id" : ObjectId("5a44a18c7d7aab074482e11e"),
"Rank" : "1/2",
"Status" : "Ok",
"position_temp" : [
"1",
"2"
]
}
{
"_id" : ObjectId("5a44a18c7d7aab074482e11f"),
"Rank" : "2/8",
"Status" : "Ok",
"position_temp" : [
"2",
"8"
]
}
My $split function is here:
{ $addFields: {"position_temp": { $split: [ "$Rank", "/" ] }}
Required form of data:
{
"_id" : ObjectId("5a44a18c7d7aab074482e11f"),
"Rank" : "2/8",
"Status" : "Ok",
"position_temp" : [2,8],
"position" : "Second"
}
{
"_id" : ObjectId("5a44a18c7d7aab074482e11d"),
"Rank" : "4/12",
"Status" : "Ok",
"position_temp" : [4,12],
"position" : "Other"
}

Complex query containing array tasks with number position in array in MongoDB [duplicate]

This question already has answers here:
Find in Double Nested Array MongoDB
(2 answers)
MongoDB: count the number of items in an array
(3 answers)
Closed 5 years ago.
I need to know, can I make complex query which will return me result with array board but only with parameters Object inside :
board.name
_id
array with (lists.list and index position in array)
length cards in array
I'm weak in mongodb so I ask if it is possible to do so, because I have order and I do not know whether to do it in the query or on the loop in the angularjs
Here is from db result with query db.getCollection('boards').find({}) (2results)
/* 1 */
{
"_id" : ObjectId("5a0b5c6da0502e2174fd849f"),
"name" : "example 1",
"users" : [
ObjectId("59cd114cea98d9326ca1c421")
],
"lists" : [
{
"list" : "example",
"_id" : ObjectId("5a0b5c7ba0502e2174fd84ae"),
"cards" : [
{
"name" : "1",
"_id" : ObjectId("5a0b5c80a0502e2174fd84b4")
},
{
"name" : "2",
"_id" : ObjectId("5a0b5c80a0502e2174fd84b3")
},
{
"name" : "3",
"_id" : ObjectId("5a0b5c80a0502e2174fd84b2")
}
]
},
{
"list" : "example 1",
"_id" : ObjectId("5a0b5c7ba0502e2174fd84ad"),
"cards" : [
{
"name" : "1",
"_id" : ObjectId("5a0b5c83a0502e2174fd84b5")
}
]
},
{
"list" : "example",
"_id" : ObjectId("5a0b5c7ba0502e2174fd84ac"),
"cards" : [
{
"name" : "2",
"_id" : ObjectId("5a0b5c85a0502e2174fd84b6")
}
]
}
],
"__v" : 0
}
/* 2 */
{
"_id" : ObjectId("5a0b5c71a0502e2174fd84a4"),
"name" : "example 2",
"users" : [
ObjectId("59cd114cea98d9326ca1c421")
],
"lists" : [
{
"list" : "example next 1",
"_id" : ObjectId("5a0b5c93a0502e2174fd84bc"),
"cards" : [
{
"name" : "1",
"_id" : ObjectId("5a0b5c95a0502e2174fd84c2")
},
{
"name" : "2",
"_id" : ObjectId("5a0b5c95a0502e2174fd84c1")
},
{
"name" : "3",
"_id" : ObjectId("5a0b5c95a0502e2174fd84c0")
}
]
},
{
"list" : "example next 2",
"_id" : ObjectId("5a0b5c93a0502e2174fd84bb"),
"cards" : [
{
"name" : "1",
"_id" : ObjectId("5a0b5c98a0502e2174fd84c5")
},
{
"name" : "2",
"_id" : ObjectId("5a0b5c98a0502e2174fd84c4")
}
]
},
{
"list" : "example next 3",
"_id" : ObjectId("5a0b5c93a0502e2174fd84ba"),
"cards" : [
{
"name" : "1",
"_id" : ObjectId("5a0b5c9aa0502e2174fd84c6")
}
]
}
],
"__v" : 0
}
Yes,
You can structure your own response, with aggregation framework .
https://docs.mongodb.com/manual/aggregation/
The most useful stages in that framework I used are:
$project: Structure what I want.
$match: Very similiar to select in sql.
$group: to make groups
$sort: to sort :D
$unwind: to unwind arrays.
There are more I think but depend on how you want structure, An excelent tutorial here:
https://www.tutorialspoint.com/mongodb/mongodb_aggregation.htm

Reformat MongoDB results from aggregate

I'm coming from SQL world and starting with MongoDB, I'm still a bit confused...
I have a collection with this structure
{
"_id" : ObjectId("5769b51f675e6190119935ec"),
"city" : "City1",
"company" : "Company1",
"country" : "Country1",
"zip" : "23345",
},{
"_id" : ObjectId("5769b51f675e6190119935ed"),
"city" : "City1",
"company" : "Company2",
"country" : "Country1",
"zip" : "1245",
},{
"_id" : ObjectId("5769b51f675e6190119935ee"),
"city" : "City2",
"company" : "Company1",
"country" : "Country1",
"zip" : "123445",
},{
"_id" : ObjectId("5769b51f675e6190119935ef"),
"city" : "City1",
"company" : "Company2",
"country" : "Country1",
"zip" : "1235445",
}
and my query,
db.getCollection('stores').aggregate([{"$group":{"_id" : {city :"$city", company : "$company"}}}])
I'm using angular and NodejS+Express to get the data from de database and I get the data with this format
[
{
_id:{
city:"City1",
company:"Compnay1"
}
},
{
_id:{
city:"City1",
company:"Company2"
}
},
{
_id:{
city:"City2",
company:"Compan1"
}
}
]
So I'm wondering if there's a way to get this query result without the _id key,
like this:
[
{
city:"City1",
company:"Compnay1"
},
{
city:"City1",
company:"Company2"
},
{
city:"City2",
company:"Compan1"
}
]
Just use $project as aggregation pipeline operator in the next pipeline stage:
db.getCollection('stores').aggregate([
{"$group":{"_id" : {city :"$city", company : "$company"}}},
{"$project": {"city": "$_id.city", "company": "$_id.company", "_id": 0}}
])

Resources