How to use Group By and concat fields as string - mongodb

I am novice at MongoDB 3.2,
Consider below example,
{ "_id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 1" }
{ "_id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 2" }
{ "_id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 3" }
How can I use Group By _id and create single field with all document fields being concatenated, below is expected output,
{ "_id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 1, GSTR 2, GSTR 3" }
I used below but it gives array,
db.getCollection('Clients').aggregate(
[
{
$group : {
_id : "$_id",
services : "$services"
}
}
]
).map( doc =>
Object.assign(
doc,
{ "services": doc.services.join(",") }
)
);
it gives output as
[{ "_id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 1, GSTR 2, GSTR 3" }]

It's working fine i checked
db.client.insert([
{ "id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 1" },
{ "id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 2" },
{ "id" : "2tLX8ALYfRvbgiurZ", "service" : "GSTR 3" }
]);
db.getCollection('client').aggregate(
[
{
$group: {
_id:"$id",
myfield: {$push: {$concat: ["$service"]}}
}
},
{
$project:{
"results": {
$reduce: {
input: "$myfield",
initialValue: '',
in: {$concat: ["$$value", ", ", "$$this"]}
}
}
}
}
]
);

docIwant = db.getCollection('Clients').aggregate(
[
{
$group : {
_id : "$_id",
services : "$services"
}
}
]
).map( doc =>
Object.assign(
doc,
{ "services": doc.services.join(",") }
)
);
return docIwant[0].

Related

Mongo find query only returns one result

Hello I have the following data structure :
[
{
"name": "a name",
"project": [
{
companyName: "a name",
contactPerson: [
{
work_email: "test#test.com"
}
]
},
{
companyName: "a name1",
contactPerson: [
{
work_email: "test1#test.com"
}
]
},
{
companyName: "a name2",
contactPerson: [
{
work_email: "test2#test.com"
}
]
},
{
companyName: "a name3",
contactPerson: [
{
work_email: "test#test.com"
}
]
},
]
}
]
With this query i want to find all projects that have the email test#test.com :
db.collection.find({
"project.contactPerson.work_email": "test#test.com"
},
{
"project.$": 1
})
It only returns the first result it finds and then it just stops. but in my data i have two projects with that email and i want to find both. here's a playground you can use to further help me if you can. Thanks in advance and much appreciated : https://mongoplayground.net/p/4Mpp7kHi98u
The positional $ operator limits the contents of an to return either:
The first element that matches the query condition on the array.
The first element if no query condition is specified for the array
(Starting in MongoDB 4.4). Ref
You can do something like following,
[
{
"$unwind": "$project"
},
{
$addFields: {
"project.contactPerson": {
$filter: {
input: "$project.contactPerson",
cond: {
$eq: [
"$$this.work_email",
"test#test.com"
]
}
}
}
}
},
{
$match: {
$expr: {
$ne: [
"$project.contactPerson",
[]
]
}
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
project: {
"$addToSet": "$project"
}
}
}
]
Working Mongo playground
db.collection.aggregate([
{
$unwind: "$project"
},
{
$match: {
"project.contactPerson.work_email": "test#test.com"
}
},
{
"$group": {
"_id": "$_id",
"name": {
"$first": "$name"
},
"project": {
"$push": {
"companyName": "$project.companyName",
"contactPersion": "$project.contactPerson"
}
}
}
}
])
//step1(problem statement related find):, find shows all projects even one of the array element of contact is matched, use an aggregate function to display specific email ids
> db.test3.find({ "project.contact.email": "abc2#email.com" }).pretty();
{
"_id" : ObjectId("5f43fdc153e34ac6967fe8ce"),
"name" : "Pega Contractors",
"project" : [
{
"pname" : "pname1",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
},
{
"pname" : "pname2",
"contact" : [
{
"email" : "abc2#email.com"
}
]
},
{
"pname" : "pname3",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
}
]
}
--
//aggregate option:
//Step1: data preparation
> db.test3.find().pretty();
{
"_id" : ObjectId("5f43fdc153e34ac6967fe8ce"),
"name" : "Pega Contractors",
"project" : [
{
"pname" : "pname1",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
},
{
"pname" : "pname2",
"contact" : [
{
"email" : "abc2#email.com"
}
]
},
{
"pname" : "pname3",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
}
]
}
>
//step2: aggregate and unwind project for the next step pipeline input
> db.test3.aggregate([ {$unwind: "$project"}]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname1", "contact" : [ { "email" : "xyz1#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname2", "contact" : [ { "email" : "abc2#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname3", "contact" : [ { "email" : "xyz1#email.com" } ] } }
//step3: Desired outcome, i.e display data specific to email
> db.test3.aggregate([
... {$unwind: "$project"},
... {$match: {"project.contact.email":"xyz1#email.com"}}
... ]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname1", "contact" : [ { "email" : "xyz1#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname3", "contact" : [ { "email" : "xyz1#email.com" } ] } }
> db.test3.aggregate([ {$unwind: "$project"}, {$match: {"project.contact.email":"acb2#email.com"}} ]);
> db.test3.aggregate([ {$unwind: "$project"}, {$match: {"project.contact.email":"abc2#email.com"}} ]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname2", "contact" : [ { "email" : "abc2#email.com" } ] } }
>

Group by array element in Mongodb

We have nested document and trying to group by array element. Our document structure looks like
/* 1 */
{
"_id" : ObjectId("5a690a4287e0e50010af1432"),
"slug" : [
"true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
],
"tags" : [
{
"id" : "59244aa6b1be5055278e9b5b",
"name" : "true crime",
"_id" : "59244aa6b1be5055278e9b5b"
},
{
"id" : "5924524db1be5055278ebd6e",
"name" : "Occult Museum",
"_id" : "5924524db1be5055278ebd6e"
},
{
"id" : "5a690f0fc1a72100110c2656",
"_id" : "5a690f0fc1a72100110c2656",
"name" : "murder mysteries"
},
{
"id" : "59244d71b1be5055278ea654",
"name" : "unsolved murders",
"_id" : "59244d71b1be5055278ea654"
}
]
}
We want to find list of all slugs group by tag name. I am trying with following and it gets result but it isn't accurate. We have hundreds of records with each tag but i only get few with my query. I am not sure what i am doing wrong here.
Thanks in advance.
// Requires official MongoShell 3.6+
db.getCollection("test").aggregate(
[
{
"$match" : {
"item_type" : "Post",
"site_id" : NumberLong(2),
"status" : NumberLong(1)
}
},
{$unwind: "$tags" },
{
"$group" : {
"_id" : {
"tags᎐name" : "$tags.name",
"slug" : "$slug"
}
}
},
{
"$project" : {
"tags.name" : "$_id.tags᎐name",
"slug" : "$_id.slug",
"_id" : NumberInt(0)
}
}
],
{
"allowDiskUse" : true
}
);
Expected output is
TagName Slug
----------
true crime "true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
"All records where tags true crime"
Instead of using slug as a part of _id you should use $push or $addToSet to accumulate them, try:
db.test.aggregate([
{
$unwind: "$tags"
},
{
$unwind: "$slug"
},
{
$group: {
_id: "$tags.name",
slugs: { $addToSet: "$slug" }
}
},
{
$project: {
_id: 1,
slugs: {
$reduce: {
input: "$slugs",
initialValue: "",
in: {
$concat: [ "$$value", ",", "$$this" ]
}
}
}
}
}
])
EDIT: to get comma separated string for slugs you can use $reduce with $concat
Output:
{ "_id" : "murder mysteries", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "Occult Museum", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "unsolved murders", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "true crime", "slugs" : ",10-most-infamous-american-murder- mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }

How to $setDifference in array & Object using Mongo DB

UserDetails
{
"_id" : "5c23536f807caa1bec00e79b",
"UID" : "1",
"name" : "A",
},
{
"_id" : "5c23536f807caa1bec00e78b",
"UID" : "2",
"name" : "B",
},
{
"_id" : "5c23536f807caa1bec00e90",
"UID" : "3",
"name" : "C"
}
UserProducts
{
"_id" : "5c23536f807caa1bec00e79c",
"UPID" : "100",
"UID" : "1",
"status" : "A"
},
{
"_id" : "5c23536f807caa1bec00e79c",
"UPID" : "200",
"UID" : "2",
"status" : "A"
},
{
"_id" : "5c23536f807caa1bec00e52c",
"UPID" : "300",
"UID" : "3",
"status" : "A"
}
Groups
{
"_id" : "5bb20d7556db6915846da55f",
"members" : {
"regularStudent" : [
"200" // UPID
],
}
},
{
"_id" : "5bb20d7556db69158468878",
"members" : {
"regularStudent" : {
"0" : "100" // UPID
}
}
}
Step 1
I have to take UID from UserDetails check with UserProducts then take UPID from UserProducts
Step 2
we have to check this UPID mapped to Groups collection or not ?.
members.regularStudent we are mapped UPID
Step 3
Suppose UPID not mapped means i want to print the UPID from from UserProducts
I have tried but couldn't complete this, kindly help me out on this.
Expected Output:
["300"]
Note: Expected Output is ["300"] , because UserProducts having UPID 100 & 200 but Groups collection mapped only 100& 200.
My Code
var queryResult = db.UserDetails.aggregate(
{
$lookup: {
from: "UserProducts",
localField: "UID",
foreignField: "UID",
as: "userProduct"
}
},
{ $unwind: "$userProduct" },
{ "$match": { "userProduct.status": "A" } },
{
"$project": { "_id" : 0, "userProduct.UPID" : 1 }
},
{
$group: {
_id: null,
userProductUPIDs: { $addToSet: "$userProduct.UPID" }
}
});
let userProductUPIDs = queryResult.toArray()[0].userProductUPIDs;
db.Groups.aggregate([
{
$unwind: "$members.regularStudent"
},
{
$group: {
_id: null,
UPIDs: { $addToSet: "$members.regularStudent" }
}
},
{
$project: {
members: {
$setDifference: [ userProductUPIDs , "$UPIDs" ]
},
_id : 0
}
}
])
My Output
{
"members" : [
"300",
"100"
]
}
You need to fix that second aggregation and get all UPIDs as an array. To achieve that you can use $cond and based on $type either return an array or use $objectToArray to run the conversion, try:
db.Groups.aggregate([
{
$project: {
students: {
$cond: [
{ $eq: [ { $type: "$members.regularStudent" }, "array" ] },
"$members.regularStudent",
{ $map: { input: { "$objectToArray": "$members.regularStudent" }, as: "x", in: "$$x.v" } }
]
}
}
},
{
$unwind: "$students"
},
{
$group: {
_id: null,
UPIDs: { $addToSet: "$students" }
}
},
{
$project: {
members: {
$setDifference: [ userProductUPIDs , "$UPIDs" ]
},
_id : 0
}
}
])

Return Multiple values from distincts group filters - Mongodb

I want to return two types of group results in one query, but it doen't work.
If you have one idea please share with me.
I have this collection:
[
{
_id: "ABC00001",
results: [
{
_id: "C0001",
status: {
_id: "stj001",
name: "status1"
},
test:{
profession: [
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst006",
"name" : "University 3"
}
},
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst002",
"name" : "University 2"
}
}
]
}
},
{
_id: "C0002",
status: {
_id: "stj002",
name: "status1"
},
test:{
profession: [
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst006",
"name" : "University 3"
}
}
]
}
},
]
},
{
_id: "ABC00002",
results: [
{
_id: "C0001",
status: {
_id: "stj002",
name: "status1"
},
test:{
profession: [
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst002",
"name" : "University 2"
}
},
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst006",
"name" : "University 3"
}
}
]
}
},
{
_id: "C0002",
status: {
_id: "stj003",
name: "status1"
},
test:{
profession: [
{
"level" : "Pregrado",
"institution" : {
"_id" : "inst006",
"name" : "University 3"
}
}
]
}
},
]
},
]
I wanna return only disctincts institutions and status in one group query like this:
institution: [
{"_id" : "inst006","name" : "University 3"},
{"_id" : "inst002", "name" : "University 2"},
]
status: [
{_id: "stj002", name: "status1"},
{_id: "stj003", name: "status1"}
]
I tried with this but doesnt work:
db.collection.aggregate(
[
{'$unwind' : '$results'},
{'$group' : { '_id' : { 'status' : {'_id'=>'$results.status._id', 'name' : '$results.status.name'}, 'count' : { '$sum' : 1 } } } },
{'$group' : { '_id' : { 'institution' : {'_id' :'$results.test.profession.institution._id', 'name':'$results.test.profession.institution.name'},
'count' : { '$sum' 1 } } }
]
)
If I work with two distincts querys with their own group it works but I need only one query returns all values, maybe I'll add more groups
If I understand your requirements correctly then this might work.
db.CollectionName.aggregate([
{"$group" : {_id : {statusid:"$results.status._id", statusname: "$results.status.name", instid:"$results.test.profession.institution._id", instname: "$results.test.profession.institution.name"}},
},
{ "$project": {
"results.status._id": 1,
"results.status.name": 1,
"results.test.profession.institution._id": 1,
"results.test.profession.institution.name": 1
}
},
{ "$sort": { "_id.statusid": 1 }},
])
Note: The JSON data needs to be formatted to make this work.
I found the solution:
db.collection.aggregate([
{'$match' : {'_id' : "CA0001"] ],
{'$unwind' : '$results'],
{'$unwind' : '$results.test'],
{'$unwind' : '$results.test.profession'],
{'$unwind' : '$results.test.skills'],
{'$group' : {
'_id' : {
"status" : {'_id':'$results.status.id', 'name':'$results.status.name'},
"institution" : {'_id':'$results.test.profession.institution._id', 'name':'$results.test.profession.institution.name'},
'profession' => {'_id':'$results.test.profession.education._id', 'description':'$results.test.profession.education.description'},
'availability' : {'_id':'$results.availability._id', 'name':'$results.availability.name'},
'skills' : {'_id':'$results.test.skills._id', 'description':'$results.test.skills.description'}
},
}
},
{'$project' : { 'status' : 1, 'institution': 1, 'profession': 1, 'skills': 1, 'availability': 1} },
{
'$group' : {
'_id' : null,
'status' : {
'$addToSet' : '$_id.status'
},
'institution' : {
'$addToSet' : '$_id.institution'
},
'profession' : {
'$addToSet' : '$_id.profession'
},
'availability' : {
'$addToSet' : '$_id.availability'
},
'skills' : {
'$addToSet' : '$_id.skills'
}
}
}
]);
it returns:
{
"_id": null,
"status": [
{
"_id": 1,
"name": "evaluado"
}
],
"institution": [
{
"_id": "inst078",
"name": "Universidad Privada del Norte"
},
{
"_id": "inst079",
"name": "Universidad San Ignacio de Loyola"
}
],
"profession": [
{
"_id": "fa059",
"description": "Estadística"
},
{
"_id": "fa063",
"description": "Ingeniería Informática"
},
"availability": [
{
"_id": "wo001",
"name": "Inmediata"
}
],
"skills": [
{
"_id": "sk366",
"description": "Pentaho"
}
]
}
All results are distincts.
I reduced time from 550ms to 43ms in programming language, comparing doing with database query and code programming using collections.

How to take the duplicate records in mongodb

Here i have two document ,in this documents childNodes array ID is duplicate means , i want to take the userID and pedagogyID of the record,as per my documents second document under childNodes array 798 is coming duplicate, so i want to take the records
Documents
{
"userID" : "A",
"pedagogyID" : "100",
"summary" : {
"LearnProgress" : {
"childNodes" : [
{
"ID" : "123",
"status" : "in-progress"
},
{
"ID" : "456",
"status" : null
},
{
"ID" : "333",
"status" : null
}
],
}
}
}
{
"userID" : "B",
"pedagogyID" : "200",
"summary" : {
"LearnProgress" : {
"childNodes" : [
{
"ID" : "789",
"status" : "in-progress"
},
{
"ID" : "1010",
"status" : null
},
{
"ID" : "789",
"status" : null
}
],
}
}
}
Expected Output
{
"userID" : "B",
"pedagogyID" : "200",
}
MY Code
db.collectionname.aggregate(
[
{"$unwind":"$summary.LearnProgress.childNodes"},
{"$group":{
"_id":{"_id":"$_id","ID":"$summary.LearnProgress.childNodes.ID"},
"userID":{"$first":"$userID"},
"pedagogyID":{"$first":"$pedagogyID"},
"count":{"$sum":1}
}},
{"$match":{"count":{"$gt":1}}},
{"$group":{"_id":{"userID":"$userID","pedagogyID":"$pedagogyID"}}},
{"$replaceRoot":{"newRoot":"$_id"}}
],
{ allowDiskUse:true }
)
You can use below aggregation.
db.colname.aggregate([
{"$unwind":"$summary.LearnProgress.childNodes"},
{"$group":{
"_id":{"_id":"$_id","ID":"$summary.LearnProgress.childNodes.ID"},
"userID":{"$first":"$userID"},
"pedagogyID":{"$first":"$pedagogyID"},
"count":{"$sum":1}
}},
{"$match":{"count":{"$gt":1}}},
{"$group":{"_id":{"userID":"$userID","pedagogyID":"$pedagogyID"}}},
{"$replaceRoot":{"newRoot":"$_id"}}
],{"allowDiskUse":true})
db.collectionname.aggregate(
// Pipeline
[
// Stage 1
{
$unwind: {
path : "$summary.LearnProgress.childNodes",
}
},
// Stage 2
{
$group: {
_id:'$summary.LearnProgress.childNodes.ID',
count:{$sum:1},
pedagogyID:{$first:'$pedagogyID'},
userID:{$first:'$userID'}
}
},
// Stage 3
{
$match: {
count:{$gt:1}
}
},
// Stage 4
{
$project: {
userID:1,
pedagogyID:1,
_id:0
}
},
]
);