Is there a way in mongoDb to merge documents based on id. For eg:
/*1*/{
"id" : "xxxxxx",
"pages" : {
"name" : "Page50-50",
"pageid" : "Page50-50",
"icon" : "/images/cmstemplates/2column.png",
"children" : []
},
"permissions" : [
{
"grpName" : "Admin",
"grants" : [
"View",
"Delete",
"Edit"
]
},
{
"grpName" : "Users",
"grants" : [
"View"
]
}
]
}
/*2*/
{
"id" : "xxxxxx",
"pages" : {
"name" : "AboutUs",
"pageid" : "AboutUs",
"icon" : "/images/cmstemplates/1column.png",
"children" : []
},
"permissions" : [
{
"grpName" : "Student",
"grants" : [
"View",
"Delete"
]
}
]
}
Expected Output:
{
"id" : "xxxxxx",
"pages" : [{
"name" : "Page50-50",
"pageid" : "Page50-50",
"icon" : "/images/2column.png",
"children" : [],
"permissions" : [
{
"grpName" : "Admin",
"grants" : [
"View",
"Delete",
"Edit"
]
},
{
"grpName" : "Users",
"grants" : [
"View"
]
}
]
},{
"name" : "AboutUs",
"pageid" : "AboutUs",
"icon" : "/images/1column.png",
"children" : [],
"permissions" : [
{
"grpName" : "Student",
"grants" : [
"View",
"Delete"
]
}
]
}]
}
The permissions params in the expected output should come inside pages, and pages should group into an array. I used $group and was able to group the pages, but i am not able to figure out how can i add permissions param inside pages. I am using mongodb 3.2.
Thanks.
Use $group
db.getCollection('Collection').aggregate([{
$group: {
"_id": "$_id",
"pages": {
$push: "$pages"
}
}
}])
Related
I want to replace the external user ids with the real user properties after $lookup, my data:
"comments" : [
{
"user_Id" : ObjectId("aaa"),
"content" : "aaaa",
"rep" : [
{
"user_Id" : ObjectId("bbb"),
"comment" : "bbbb",
},
{
"user_Id" : ObjectId("ccc"),
"comment" : "cccc",
}
]
},
{
"user_Id" : ObjectId("ddd"),
"content" : "ddd",
"rep" : [ ]
}
]
User collection:
"users" : [
{
"_id" : ObjectId("aaa"),
"name" : "user1",
"email" : "test1#test.com",
},
{
"_id" : ObjectId("bbb"),
"username" : "user2",
"email" : "test2#test.com",
}
]
What i want to archieve:
"comments" : [
{
"user" : {
"_id" : ObjectId("aaa"),
"name" : "user1",
"email" : "test1#test.com",
}
"content" : "aaaa",
"rep" : [
{
"userId" : {
"_id" : ObjectId("bbb"),
"username" : "user2",
"email" : "test2#test.com",
},
"comment" : "bbbb",
},
{
"user" : {
"_id" : ObjectId("aaa"),
"name" : "user1",
"email" : "test1#test.com",
},
"comment" : "cccc",
}
]
},
{
"user" : {
"_id" : ObjectId("bbb"),
"username" : "user2",
"email" : "test2#test.com",
},
"content" : "ddd",
"rep" : [ ]
}
]
Right now i managed to get my user info from the external id but i'm going crazy trying to get the user object inside the replies too, i tried to group after grouping but nothing to do, this is what i did:
db.pages.aggregate([
{
$match: { _id: ObjectId('5db599f3fffdee1c822269e0b3') }
},
{
$project: {
comments: 1,
}
},
{ $unwind: '$comments' },
{
$lookup:
{
from: 'users',
localField: 'comments.user_Id',
foreignField: '_id',
as: 'us'
}
},
{ $unwind: '$us' },
{
$group: {
_id: {
user: {
id: '$us._id',
name: '$us.username',
email: '$us.email',
},
comments: {
comment: '$comments.comment',
rep: '$comments.rep'
},
}
}
}
]).pretty()
Say if I have a result like this:
{
"_id" : ObjectId("5b722d06c23b5f2bd0329a41"),
"name" : "test",
"item" : {
"_id" : ObjectId("5b722d07c23b5f2bd0329a53"),
"display_name" : "",
"image" : "http://via.placeholder.com/700x500/ffffff/000000/?text=No%20Image&",
"is_private" : true,
"details" : [
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a44"),
"title" : "Name",
"content" : "",
"order" : 0
},
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a43"),
"title" : "Price",
"content" : "",
"order" : 1
},
{
"is_private" : false,
"type" : "text",
"_id" : ObjectId("5b722d06c23b5f2bd0329a42"),
"title" : "Company",
"content" : "",
"order" : 2
}
],
"tags" : [ ],
"__v" : 0
}
}
and I want to filter by item.details.is_private, how should I do this? I want to return all properties of item but filter out any item.details.is_private if it is true
I am currently projecting it as:
{
"$project": {
name: 1,
item: 1
}
}
but am not sure how to implement $filter in this setting
You can try using $addsFields with $filter aggregation
db.collection.aggregate([
{ "$addFields": {
"item.details": {
"$filter": {
"input": "$item.details",
"as": "detail",
"cond": {
"$eq": [ "$$detail.is_private", true ]
}
}
}
}}
])
I have the following Menus Collection on MongoDB. It has values like Permission and Submenu.
{
"_id" : ObjectId("5b42c5c8a80e160a146822e1"),
"HasSubmenu" : "false",
"Icon" : "fas fa-home",
"MenuCode" : "PaginaInicial",
"MenuName" : "Página Inicial",
"MenuState" : "paginainicial",
"Permission" : 1
"Submenu" : [ ],
},
{
"_id" : ObjectId("5b42c5c8a80e160a146822e2"),
"HasSubmenu" : "true",
"Icon" : "far fa-file-alt",
"MenuCode" : "FormulariosApoio",
"MenuName" : "Formularios de Apoio",
"MenuState" : "",
"Permission" : 1
"Submenu" : [
{
"MenuState" : "tiposassociados",
"MenuName" : "Tipos Associados",
"MenuCode" : "TiposAssociados",
"Icon" : "fas fa-tags",
"HasSubmenu" : false,
"Permission" : 1
},
{
"MenuState" : "naturalidades",
"MenuCode" : "Naturalidade",
"MenuName" : "Naturalidade",
"Icon" : "fas fa-globe-asia",
"HasSubmenu" : false,
"Permission" : 4
},
{
"MenuState" : "nacionalidades",
"MenuCode" : "Nacionalidade",
"MenuName" : "Nacionalidade",
"Icon" : "fas fa-globe-americas",
"HasSubmenu" : false,
"Permission" : 4
},
]
}
I need help returning, only the Menus and Submenus that has the value { "Permission" : 1 }, evend if the Menus, don`t have any Submenus
Tried this one but it doens`t ssm to work.
db.getCollection("menus").find({
$and: [
{"Submenu" : { $elemMatch : {"Permission": 1}}},
{"Permission": 1},
]
});
You can try with $filter aggregation
db.collection.aggregate([
{ "$match": { "Permission": 1 } },
{ "$addFields": {
"Submenu": {
"$filter": {
"input": "$Submenu",
"as": "submenu",
"cond": {
"$eq": [ "$$submenu.Permission", 1 ]
}
}
}
}}
])
I would like to create an unique list of array values inside a subdocument.
Document:
{
"_id" : ObjectId("5aee0e3c059638093b69c8b3"),
"firstname" : "John",
"lastname" : "Doe",
"websites" : [
{
"_id" : ObjectId("123"),
"key" : "website2",
"url" : "www.xxx.com",
"tags" : [
"php",
"python",
"java"
]
},
{
"_id" : ObjectId("456"),
"key" : "website2",
"url" : "www.yyy.com",
"tags" : [
"java",
"php"
]
},
{
"_id" : ObjectId("789"),
"key" : "website3",
"url" : "www.zzz.com",
"tags" : [
"java",
"html",
"css"
]
}
]
}
Expected output:
{
"_id" : ObjectId("5aee0e3c059638093b69c8b3"),
"firstname" : "John",
"lastname" : "Doe",
"unique_tags": [
"java",
"php",
"python",
"html",
"css",
],
"websites" : [
{
"_id" : ObjectId("123"),
"key" : "website2",
"url" : "www.xxx.com",
"tags" : [
"php",
"python",
"java"
]
},
{
"_id" : ObjectId("456"),
"key" : "website2",
"url" : "www.yyy.com",
"tags" : [
"java",
"php"
]
},
{
"_id" : ObjectId("789"),
"key" : "website3",
"url" : "www.zzz.com",
"tags" : [
"java",
"html",
"css"
]
}
]
}
It looks like Mongo has a distinct functionality, but this does not work inside an aggregate query (right?!).
Also tried to unwind on websites.tags and use the addToSet functionality but it also hasn't the right output.
Any ideas?
You can try below aggregation:
db.col.aggregate([
{
$addFields: {
unique_tags: {
$reduce: {
input: {
$concatArrays: {
$map: {
input: "$websites",
as: "website",
in: "$$website.tags"
}
}
},
initialValue: [],
in: { $setUnion : ["$$value", "$$this"]}
}
}
}
}
])
To flatten an array of arrays (websites -> tags) you can use $map with $concatArrays. Then you'll get an array of all tags from all websites. To get only unique values you can use $reduce with $setUnion (which drops duplicates).
I have the collection named companies as below.
I want to query the url corresponding to C1S1category1 . I do not know which companyName it belongs and which catergories it belongs to.
Please can you let me know what query I need to use in Mongoshell to query the document having catergoryname as C1S1category1
{"companyName": "C1",
"url": "www.com1",
"categories" : [
{"SlNo" : 1,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C1S1category1",
"Url" : "www.com3"
},
{
"CatergoryName":"C1S1category2",
"Url" : "www.com3"
}
]
},
{
"SlNo" : 2,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C1S2category1",
"Url" : "www.com3"
},
{
"CatergoryName":"C1S2category2",
"Url" : "www.com3"
}
]
}
]
},
{"companyName": "C2",
"url": "www.com21",
"categories" : [
{"SlNo" : 1,
"url" : "www.com22",
"subcategories" : [
{
"CatergoryName":"C2S1category1",
"Url" : "www.com23"
},
{
"CatergoryName":"C2S1category2",
"Url" : "www.com23"
}
]
},
{
"SlNo" : 2,
"url" : "www.com1",
"subcategories" : [
{
"CatergoryName":"C2S2category1",
"Url" : "www.com23"
},
{
"CatergoryName":"C2S2category2",
"Url" : "www.com23"
}
]
}
]
}
You need to use $elemMatch to get required output as following:
db.collection.find({
"categories": {
$elemMatch: {
subcategories: {
$elemMatch: {
CatergoryName: "C1S1category1"
}
}
}
}
},{"categories.$":1,"companyName":1,"url":1}).pretty()