[
{
"_id": '1',
"role":'admin',
"created":"0",
},
{
"_id": '2',
"role":'vendor',
"created":"1",
},
{
"_id": '3',
"role":'cus',
"created":"1",
},
{
"_id": '4',
"role":'cus',
"created":"1",
},
{
"_id": '5',
"role":'admin1',
"created":"1",
},
{
"_id": '6',
"role":'support',
"created":"5",
},
{
"_id": '7',
"role":'support',
"created":"5",
},
]
Would like to this type of result
Thanks in Advance
[
{
_id: 1,
created: "admin",
counts: [
{
role: "vendor",
count: 1
},
{
role: "cus",
count: 2
}
]
},
{
_id: 5,
created: "admin1",
counts: [
{
role: "support",
count: 2
}
]
}
]
You can group by role and count created using this query.
db.<yourCollectionName>.aggregate ( { $group : { _id: "$role" , count: { $sum:1 } } })
Above query returns output like this...
{ "_id" : "cus", "count" : 2 }
Another variation of aggregation is..
db.counts.aggregate([{ $group: { _id: "$role", count: { $sum:1 }, Data: { $push: "$$ROOT" } } }]).pretty()
Above query returns output like this...
{
"_id" : "cus",
"count" : 2,
"Data" : [
{
"_id" : ObjectId("5db368e9d130deb5c19f35c8"),
"role" : "cus",
"created" : "1"
},
{
"_id" : ObjectId("5db36913d130deb5c19f35c9"),
"role" : "cus",
"created" : "1"
}
]
}
Related
I have a MongoDB collection called books.
An example of a document is:
{
"_id" : ObjectId("62bf10951fecaed4dba275b1"),
"name" : "Library 1",
"positions" : [
{
"number" : 2,
"nodes" : [
{
"number" : 2,
"bookId" : "6254674d3711f90bd8e76036"
},
{
"number" : 1,
"bookId" : "621e9b5aa7951d0be4516c18"
}
]
},
{
"number" : 1,
"nodes" : [
{
"number" : 1,
"bookId" : "6254674d3711f90bd8e76037"
},
{
"number" : 3,
"bookId" : "6254674d3711f90bd8e76039"
},
{
"number" : 2,
"bookId" : "6254674d3711f90bd8e76035"
}
]
}
]
}
I need to run a query that, based on a book ID, returns the name, the positions.number and the positions.node.number.
For example, if I search for the ID 6254674d3711f90bd8e76035, it should return:
{
_id: ObjectId("62bf10951fecaed4dba275b1"),
name: "Library 1",
positions: {
number: 1,
nodes: {
number: 2
}
}
}
So far, this is what I came out with:
db.getCollection('books').aggregate([
{ $match: { "positions.nodes.bookId": "6254674d3711f90bd8e76035" } },
{ $project: { name: 1, "positions.number": 1, "positions.nodes.number": 1 } }
])
Unfortunately, this returns every single node. I might need something that says:
"Select name, position.number, position.nodes.number where bookId = 6254674d3711f90bd8e76035"
Any help is appreciated.
Thanks
Solved:
db.getCollection('books').aggregate([
{
$match: {"positions.nodes.books": "6254674d3711f90bd8e76035"}
},
{
$unwind: "$positions"
},
{
$unwind: "$positions.nodes"
},
{
$match: {"positions.nodes.books": "6254674d3711f90bd8e76035"}
},
])
Document in my collection looks like one below. How to count the duplicates amount when two pair of strings (user and a32cc286-256b-40e5-fc5d-5ecbdc341ab1) is the same as in example? And how to remove one of these pair?
"_id" : ObjectId("5ea3138daee55c0001eac29f"),
"linkRole" : [
{
"role" : "admin",
"Organization" : "a32cc286-256b-40e5-fc5d-5ecbdc341ab1"
},
{
"role" : "superadmin",
"Organization" : "a32cc286-256b-40e5-fc5d-5ecbdc341ab1"
},
{
"role" : "user",
"Organization" : "a32cc286-256b-40e5-fc5d-5ecbdc341ab1"
},
{
"role" : "user",
"Organization" : "a32cc286-256b-40e5-fc5d-5ecbdc341ab1"
},
{
"role" : "admin",
"Organization" : "dd79f23d-2382-4eb7-a2f3-634890eba0bb"
},
{
"role" : "superadmin",
"Organization" : "dd79f23d-2382-4eb7-a2f3-634890eba0bb"
}]
Same document:
linkRole[0].role:admin
linkRoles[0].Organization:a32cc286-256b-40e5-fc5d-5ecbdc341ab1
linkRole[1].role:superadmin
linkRoles[1].Organization:a32cc286-256b-40e5-fc5d-5ecbdc341ab1
linkRole[2].role:user
linkRoles[2].Organization:a32cc286-256b-40e5-fc5d-5ecbdc341ab1
linkRole[3].role:user
linkRoles[3].Organization:a32cc286-256b-40e5-fc5d-5ecbdc341ab1
linkRole[4].role:admin
linkRoles[4].Organization:dd79f23d-2382-4eb7-a2f3-634890eba0bb
linkRole[5].role:superadmin
linkRoles[5].Organization:dd79f23d-2382-4eb7-a2f3-634890eba0bb
I use this code to get duplicates. And have documents with 2..3..10 of them. Now i need to remove all of them, but save 1 unique string.
db.users.aggregate(
{$unwind: "$linkRole"},
{$group: {"_id": {org: "$linkRole.Organization", role: "$linkRole.role"},
count: {"$sum": 1}}},
{$match: { "count": { "$gte": 2 }}})
I think this aggregation can help you
db.collection.aggregate([
{
"$unwind": "$linkRole"
},
{
"$group": {
"_id": {
"Organization": "$linkRole.Organization",
"role": "$linkRole.role"
}
}
},
{
"$project": {
"_id": 0,
"role": "$_id.role",
"Organization": "$_id.Organization"
}
}
])
Playground
pipeline = [
{$unwind: "$linkRole"},
{$group: {
_id: {
d_id: "$_id",
role: "$linkRole.role",
Organization: "$linkRole.Organization"
},
count: {$sum: 1}
}},
{$match:{count: {$gt: 1}}}
]
db.users.aggregate(pipeline).forEach(a => {
user = db.users.findOne({_id: a._id.d_id});
for (let i = 1; i < a.count; i++) {
user.linkRole.splice(
user.linkRole.findIndex(lr => lr.role === a._id.role && lr.Organization === a._id.Organization),
1
)
}
db.users.save(user)
})
Thank you, #AlexoLive from habr.
I have a USER table with documents:
{
_id: 1,
name: 'funny-guy43',
image: '../../../img1.jpg',
friends: [2, 3]
},
{
_id: 2,
name: 'SurfinGirl3',
image: '../../../img2.jpg',
friends: []
},
{
_id: 3,
name: 'FooBarMan',
image: '../../../img3.jpg',
friends: [2]
}
friends is an array of USER _ids. (1) I want to get user by _id, (2) look at his friends and (3) query the USER table with the friend ids to return all friends.
for example, find user 1, query the table based on his friends 2 and 3, and return 2 and 3.
Can I do that in one transaction? Or do I query the table to get user array of friends, then query the table again with array of friends ids.
I'm using .Net Core if that matters.
I am very open to alternative approaches as well.
It is, in fact, possible to do this in one transaction. Or, to be more exact, in one aggregation.
I would first split the users into 2 different subsets, one called searched_user and the other other_users, where searched_user will have only the user we are searching for and other_users will have everyone else. We can do that using $facet. Here is the idea:
{
"$facet": {
"searched_user": [
{
$match: {
_id: 1
}
}
],
"other_users": [
{
$match: {
_id: {
$ne: 1
}
}
}
]
}
}
Once they are separated like this, we can search the other_users subset using the friend ids from the searched_user. So here is the full aggregation:
db.collection.aggregate([
{
"$facet": {
"searched_user": [
{
$match: {
_id: 1
}
}
],
"other_users": [
{
$match: {
_id: {
$ne: 1
}
}
}
]
}
},
{
"$unwind": "$searched_user"
},
{
$project: {
user_friends: {
$filter: {
input: "$other_users",
as: "other_users",
cond: {
$in: [
"$$other_users._id",
"$searched_user.friends"
]
}
}
}
}
}
])
Here we are looking for user 1 and the result will be user 1's friends.
[
{
"user_friends": [
{
"_id": 2,
"friends": [],
"image": "../../../img2.jpg",
"name": "SurfinGirl3"
},
{
"_id": 3,
"friends": [
2
],
"image": "../../../img3.jpg",
"name": "FooBarMan"
}
]
}
]
Playground: https://mongoplayground.net/p/-8pNnQXg8r6
You can achieve this by using lookup in aggregation, Tried it with MongoDB version v4.2.11.
db.users.aggregate([
{
'$match': {
'_id': 1,
}
},
{
'$lookup': {
'from' : 'users',
'let' : {
'friendIds': '$friends',
},
'pipeline': [
{
'$match':{
'$expr': {'$in': [ '$_id', '$$friendIds']}
}
}
],
'as': 'friendsArr'
}
}
])
Result:
[
{
"_id" : 1,
"name" : "funny-guy43",
"image" : "../../../img1.jpg",
"friends" : [
2,
3
],
"friendsArr" : [
{
"_id" : 2,
"name" : "SurfinGirl3",
"image" : "../../../img2.jpg",
"friends" : [ ]
},
{
"_id" : 3,
"name" : "FooBarMan",
"image" : "../../../img3.jpg",
"friends" : [
2
]
}
]
}
]
Before the question, I'm extremely new to mongo DB and NoSQL.
I'm having two collections in my database:
users:
{
"_id" : ObjectId("5f1efeece50f2b25d4be2de2"),
"name" : {
"familyName" : "Doe",
"givenName" : "John"
},
"email" : "johndoe#example.com",
"threads" : [ObjectId("5f1f00f31abb0e3f107fbf93"), ObjectId("5f1f0725850eca800c70ef9e") ] }
}
threads:
{
"_id" : ObjectId("5f1f0725850eca800c70ef9e"),
"thread_participants" : [ ObjectId("5f1efeece50f2b25d4be2de2"), ObjectId("5f1eff1ae50f2b25d4be2de4") ],
"date_created" : ISODate("2020-07-27T16:25:19.702Z") }
}
I want to get all the threads which an user is involved in with the other user's info nested inside.
Something like:
{
"_id" : ObjectId("5f1f0725850eca800c70ef9e"),
"thread_participants" :
[
{
"name" : {
"familyName" : "Doe",
"givenName" : "John"
},
"email" : "johndoe#example.com",
},
{
"name" : {
"familyName" : "Doe",
"givenName" : "Monica"
},
"email" : "monicadoe#example.com",
}
],
"date_created" : ISODate("2020-07-27T16:25:19.702Z") }
},
...,
...,
...
How do I go about this?
You can use $lookup to "join" the data from both collections:
db.threads.aggregate([
{
$lookup: {
from: "$users",
let: { participants: "$thread_participants" },
pipeline: [
{
$match: {
$expr: {
$in: [ "$_id", "$$participants" ]
}
}
},
{
$project: {
_id: 1,
email: 1,
name: 1
}
}
],
as: "thread_participants"
}
}
])
Mongo Playground
I have this 'Sales' collection and a sample of it looks like this:
[
{cusID: 'a412q39x',
cusCountry: 'MEX',
itemPurchased: 'Toy_A'
},
{cusID: 'r760e11s',
cusCountry: 'USA',
itemPurchased: 'Toy_B'
},
{cusID: 'g723f01z',
cusCountry: 'USA',
itemPurchased: 'Toy_C'
},
{cusID: 'h277p01c',
cusCountry: 'CAN',
itemPurchased: 'Toy_B'
}
]
This is the result I am hoping to achieve.
[
{item: 'Toy_A',
USA: 4,
MEX: 2,
CAN: 1,
BRA: 0
},
{item: 'Toy_B',
USA: 3,
MEX: 0,
CAN: 2,
BRA: 1
}
]
I tried:
{
$group:{_id:{toy:'$itemPurchased', country: $cusCountry'},'cnt':{'$sum': 1}}
}
The result was not what I wanted.
[
{
_id.toy: 'Toy_A',
_id.country: 'BRA',
cnt: 43
},
{
_id.toy: 'Toy_A',
_id.country: 'USA',
cnt: 102
},
{
_id.toy: 'Toy_A',
_id.country: 'JPN',
cnt: 72
},
{
_id.toy: 'Toy_B',
_id.country: 'CAN',
cnt: 32
}
]
I have also experimented with $facet but to no avail. Mongo gurus, please enlighten. Thanks in advance.
Try as below:
db.collection.aggregate([
{
$group: { _id: '$itemPurchased' , items: { $push: { "country" : "$cusCountry", "count": { $sum :1} } } }
},
{
"$project": {
"countryCounts": {
"$arrayToObject": {
"$map": {
"input": "$items",
"as": "item",
"in": {
"k": "$$item.country",
"v": "$$item.count",
}
}
}
}
}
},
{ $replaceRoot: { newRoot: { "$mergeObjects":[ "$countryCounts" , { "item":"$_id"} ] } } }
])
You will get the result like below:
{
"USA" : 1,
"item" : "Toy_C"
},
/* 2 */
{
"USA" : 1,
"CAN" : 1,
"item" : "Toy_B"
},
/* 3 */
{
"MEX" : 1,
"item" : "Toy_A"
}