How do get the last substring using the MongoDB aggregation framework? - mongodb

Let's say I have these documents
> db.coll.find().toArray()
[
{
"_id" : ObjectId("5a36c3e218948d0722457078"),
"locality" : "Nasimi, Baku, Azerbaijan"
},
{
"_id" : ObjectId("5a36c3e218948d0722457079"),
"locality" : "Garland, TX, USA"
},
{
"_id" : ObjectId("5a36c3e218948d072245707a"),
"locality" : "Halytskyi District, Lviv, Lviv Oblast, Ukraine"
},
{
"_id" : ObjectId("5a36c3e218948d072245707b"),
"locality" : "Tozeur, Tunisia"
}
]
I would like to get only the country, i.e. whatever is after the last comma (', ').
e.g.
[
"Azerbaijan",
"USA",
"Ukraine",
"Tunisia"
]
I've managed to get the index of the first comma and what is after that but I can't figure out how to to get the last one.
db.coll
.aggregate([
{
$project: {
lastIndexOf: { $indexOfBytes: [ '$locality', ', ' ] },
locality: '$locality',
}
},
{
$project: {
lastIndexOfPlusTwo: { $add: [ '$lastIndexOf', 2 ] },
locality: '$locality',
}
},
{
$project: { country: { $substr: [ '$locality', '$lastIndexOfPlusTwo', -1 ] } }
}
]).pretty()
{
"_id" : ObjectId("5a36c3e218948d0722457078"),
"country" : "Baku, Azerbaijan"
}
{
"_id" : ObjectId("5a36c3e218948d0722457079"),
"country" : "TX, USA"
}
{
"_id" : ObjectId("5a36c3e218948d072245707a"),
"country" : "Lviv, Lviv Oblast, Ukraine"
}
{
"_id" : ObjectId("5a36c3e218948d072245707b"),
"country" : "Tunisia"
}
This works but it loads all the results in memory in the JavaScript Mongo Shell but would be ideal if it can be done with a single MongoDB aggregation command.
var res2 = db.coll.aggregate();
res2 = res2.toArray().map(function(doc) {
var lastIndex = doc.locality.lastIndexOf(',');
return doc.locality.slice(lastIndex + 2);
});
[ "Azerbaijan", "USA", "Ukraine", "Tunisia" ]
Maybe with $let, $split?

You can try below aggregation query.
{"$arrayElemAt":["$$locality",-1]} to access the last element from the array.
db.coll.aggregate([{"$project":{
"_id":0,
"last":{
"$let":{
"vars":{"locality":{"$split":["$locality",","]}},
"in":{"$arrayElemAt":["$$locality",-1]}
}
}
}}])

Related

MongoDb find with nested array

Lets say I have this kind of collection
{
"_id" :"A",
"title" : "TITLE1",
"brand" : [
{
"brand_id" : "B",
"varients" : [
{
"name" : "RED ",
"price" : 5.0
}
]
},
{
"brand_id" : "C",
"varients" : [
{
"name" : "GREEN",
"price" : 5.0
}
]
},
{
"brand_id" : "D",
"varients" : [
{
"name" : "Others",
"price" : 0.0
}
]
}
],
}
I then want to select one and ONLY the nested data of variants. Have tried with the following statement without any success.
db.testing.findOne( {_id: "A", "brand.brand_id" : 'D'} )
Expected output
"varients" : [
{
"name" : "Others",
"price" : 0.0
}
]
Using findOne you can't get the subset or nest content of the document in the response, but yes using aggregation you can get it in a way you want it
Check out this aggregation pipeline:
[
{
'$match': {
'_id': 'A'
}
}, {
'$unwind': {
'path': '$brand'
}
}, {
'$match': {
'brand.brand_id': 'D'
}
}, {
'$project': {
'varients': '$brand.varients',
'_id': 0
}
}
]

Merge two documents and reshape with arrays

Input data
[
{
"_id" : ObjectId("xxx"),
"ParentNumber" : "12345",
"ChildNumber" : "A123"
},
{
"_id" : ObjectId("yyy"),
"ParentNumber" : "12345",
"ChildNumber" : "B123"
},
{
"_id" : ObjectId("zzz"),
"ParentNumber" : "6789",
"ChildNumber" : "C123"
}
]
Output Needed
[
{
"_id" : ObjectId("aaa"),
"ParentNumber" : "12345",
"Children":[
{ "ChildNumber" : "A123"},
{ "ChildNumber" : "B123"}
]
},
{
"_id" : ObjectId("bbb"),
"ParentNumber" : "6789",
"Children":[
{ "ChildNumber" : "C123"}
]
}
]
I tried the following but can't figure out how to group the parent numbers with children.
db.test.aggregate
(
[
{
$project:
{
"_id" : ObjectId(),
"ParentNumber" : "$ParentNumber",
"Children" : [
{
"ChildNumber" : "$ChildNumber"
}
]
}
}
]
)
I referred to the merge function in mongodb but I can't figure out how to compare one document to another based on a condition and return a result with array.
Thank you
This gives the desired result. Try this:
[{$group: {
_id: "$ParentNumber",
children: {
$push:{'ChildNumber':'$ChildNumber'}
},
}}, {$project: {
"ParentNumber":"$_id",
children:1
}}]
Check this PS: it will not show the objectId of the parent
db.collection.aggregate([
{
$group: {
_id: "$ParentNumber",
Children: {
$push: "$$ROOT"
},
},
},
{
"$project": {
_id: 0,
ParentNumber: "$_id",
Children: {
"ChildNumber": "$Children.ChildNumber"
}
}
}
])

Closed: I want to return list of ids in my aggregate query, i am new to mongodb

I am using below aggregate query to get the list of restaurant matches keyword search "chinese" within the list of ids passed,
db.business.aggregate([
{
$match:{
$text:{
$search:"chinese"
}
}
},
{
$match:{
"_id":{
$in:[
ObjectId("571453a82ece1392240f7b91"),
ObjectId("5714537b2ece1392240f7b8c"),
ObjectId("5714539a2ece1392240f7b8e"),
ObjectId("571453962ece1392240f7b8d")
]
}
}
},
])
Below is the sample data in mongodb.
{
"_id" : ObjectId("571453b32ece1392240f7b93"),
"_class" : "com.halal.sa.data.entities.Business",
"name" : "Chillies",
"description" : "nice restaurant",
"cuisine" : [
"veg-nonveg",
"chinese",
"kabab"
],
"address" : {
"streetAddress" : "1000 bentley road",
"city" : "marietta",
"pincode" : 30067,
"landmark" : "near delk road",
"location" : {
"type" : "Point",
"coordinates" : [
-84.4774305,
33.9202151
]
}
},
"phone" : 123,
"email" : "my#email.com",
"ownerEmail" : "test#email",
"status" : "2",
"website" : "test.com",
"authenticity" : "1"
}
please let me know the exact modified aggregate query which will only return list of _ids instead of returning all the documents from the collection. Thanks in advance
The way I see to have really only an array of ids (like you do with distinct in find), would be by using $group
db.business.aggregate([
{
$match:{
$text:{
$search:"chinese"
}
}
},
{
$match:{
"_id": {
$in: [
ObjectId("571453a82ece1392240f7b91"),
ObjectId("5714537b2ece1392240f7b8c"),
ObjectId("5714539a2ece1392240f7b8e"),
ObjectId("571453962ece1392240f7b8d")
]
}
}
},
{ $group: { _id: null, ids: { $push: "$$ROOT._id" } } }
]);
The result would give you basically something like
[
{
_id: null,
ids: [/* Your ids */],
}
]
I got it just used the $project in the query, thats it :-)
db.business.aggregate([
{ $match: { $text: { $search: "chinese" } } },
{ $match: { "_id": {$in : [ObjectId("571453a82ece1392240f7b91"), ObjectId("5714537b2ece1392240f7b8c"),ObjectId("5714539a2ece1392240f7b8e"),ObjectId("571453962ece1392240f7b8d")]} } },
{$project: {"_id": "$_id"}}
])

MongoDB Aggregations - Is it possible to get matching values instead of sum, count, avg etc

See the document below,
[
{
"memberId": "m1",
"positionId": "pos1",
"projectId": "prj1"
},
{
"memberId": "m1",
"positionId": "pos2",
"projectId": "prj1"
},
{
"memberId": "m1",
"positionId": "pos3",
"projectId": "prj2"
},
{
"memberId": "m1",
"positionId": "pos5",
"projectId": "prj2"
},
{
"memberId": "m2",
"positionId": "pos3",
"projectId": "prj2"
}
]
I need to generate an output, for a given memberId,
group by projectIds and return with associate positionIds for that projectId
Say,
{
"result" : [
{
"_id" : {
"project" : "prj2",
"position" : ["pos5", "pos3"]
}
},
{
"_id" : {
"project" : "prj1",
"position" : ["pos2","pos1"]
}
}
]}
You can't use the $push operator to create your compound _id field. The best thing to do is $group by "projectId' and return "position" as array.
db.collection.aggregate([
{ '$group': {
'_id': '$projectId',
'position': { '$push': '$positionId' }
}}
])
Which returns:
{ "_id" : "prj2", "position" : [ "pos3", "pos5", "pos3" ] }
{ "_id" : "prj1", "position" : [ "pos1", "pos2" ] }
But if you really feel the need to have a compound _id field you need one more $group stage.
db.collection.aggregate([
{ '$group': {
'_id': '$projectId',
'position': { '$push': '$positionId' }
}},
{ '$group': {
'_id': {
'project': '$_id',
'position': '$position'
}
}}
])
Which yields:
{ "_id" : { "project" : "prj1", "position" : [ "pos1", "pos2" ] } }
{ "_id" : { "project" : "prj2", "position" : [ "pos3", "pos5", "pos3" ] } }
This aggregation could help, its result is the same as the output you have mentioned.
db.test.aggregate(
[
{
$group : {
_id : {"project" : "$projectId"},
position: { $addToSet:"$positionId" }
}
}
]
)
db.collection.aggregate([
{$match:{"memberId" : "m1"}},
{$group:{_id:"$projectId", positions:{$addToSet:"$positionId"}}},
{$project:{_id:0, "project":"$_id", positions:1}}
])
OUTPUT
{
"result" : [
{
"positions" : [
"pos5",
"pos3"
],
"project" : "prj2"
},
{
"positions" : [
"pos2",
"pos1"
],
"project" : "prj1"
}
],
"ok" : 1
}

Find exactly match array or having all value of array in MongoDb

I have collection entry like that
[
{
shape : [{id:1,status:true},{id:2,status:false}]
},
{
shape : [{id:1,status:true}]
}
]
I want to fetch data which exactly match array , means contain all ele. of array.
Ex. where shape.id = [1,2] / [ {id: [1,2] } ] (any one is prefer)
then it should return only
[
{
shape : [{id:1,status:true},{id:2,status:false}]
}
]
So help me if is there any native mongodb query .
Thanks
--ND
Here is much simpler query;
db.shapes.find({'shape.id':{$all:[1,2]},shape:{$size:2}});
If mongo documents as below
{
"_id" : ObjectId("54eeb68c8716ec70106ee33b"),
"shapeSize" : [
{
"shape" : [
{
"id" : 1,
"status" : true
},
{
"id" : 2,
"status" : false
}
]
},
{
"shape" : [
{
"id" : 1,
"status" : true
}
]
}
]
}
Then used below aggregation to match the criteria
db.collectionName.aggregate({
"$unwind": "$shapeSize"
}, {
"$match": {
"$and": [{
"shapeSize.shape.id": 2
}, {
"shapeSize.shape.id": 1
}]
}
}, {
"$project": {
"_id": 0,
"shape": "$shapeSize.shape"
}
})