How to get result count role on behalf of created? - arrays

[
{
"_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

MongoDB: retrieve only certain properties of a document after matching

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"}
},
])

How to find and remove duplicates of paired data that in an array?

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.

Mongodb user table with friends

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
]
}
]
}
]

MongoDB joining across array of ids

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

How to do pivoting on MongoDB?

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"
}

Resources