MongoDB - Get data in date sections from an array - javascript

I am new to MongoDB, I want to get data in sections from the array.
{
"name":"User name",
"messages":[
{
"message":"Message 1",
"date":"2022-05-12T00:00:00.000Z"
},
{
"message":"Message 2",
"date":"2022-05-12T00:00:00.000Z"
},
{
"message":"Message 3",
"date":"2022-05-13T00:00:00.000Z"
},
{
"message":"Message 4",
"date":"2022-05-13T00:00:00.000Z"
},
{
"message":"Message 5",
"date":"2022-05-13T00:00:00.000Z"
}
]
}
The results I want are
[
{
"date":"2022-05-12T00:00:00.000Z",
"messages":[
{
"message":"Message 1",
"date":"2022-05-12T00:00:00.000Z"
},
{
"message":"Message 2",
"date":"2022-05-12T00:00:00.000Z"
}
]
},
{
"date":"2022-05-13T00:00:00.000Z",
"messages":[
{
"message":"Message 3",
"date":"2022-05-13T00:00:00.000Z"
},
{
"message":"Message 4",
"date":"2022-05-13T00:00:00.000Z"
},
{
"message":"Message 5",
"date":"2022-05-13T00:00:00.000Z"
}
]
}
]
I'm not familiar with MongoDB aggregation, I have looked at many questions on stack overflow but didn't find any that helped me.
Is this possible to do? If yes any help would be greatly appreciated. :)

You can use aggregation to get your desired output.
db.collection.aggregate([
{
$unwind: "$messages"
},
{
$group: {
_id: "$messages.date",
messages: {
$push: "$messages"
}
}
},
{
$project: {
_id: 0,
date: "$_id",
messages: 1
}
}
])

$unwind - Deconstruct messages array to multiple documents.
$group - Group by messages.date and add messages document into messages array.
$project - Decorate output documents.
db.collection.aggregate([
{
$unwind: "$messages"
},
{
$group: {
_id: "$messages.date",
messages: {
$push: "$messages"
}
}
},
{
$project: {
_id: 0,
date: "$_id",
messages: 1
}
}
])
Sample Mongo Playground

Related

Add alias to the collection targeted in lookup

I am a beginner in MongoDB. I will try my best to explain this as easy as possible, so I will take an internet example of collection, instead of the more complicated schema I am working with!
I have two collections as follows:
Users:
[
{
"_id":{"$oid":"610bcc467b0c4008346547b8"},
"name":"xyz",
"email":"xyz#gmail.com",
"password":"xyz",
"gender":"MALE"
}
]
Posts:
[
{
"_id": {"$oid":"610bce417b0c4008346547bc"},
"image":"myImage 1",
"caption":"r/Mars",
"user_id":"610bcc467b0c4008346547b8"
},
{
"_id": {"$oid":"610bce417b0c4008346547be"},
"image":"myImage 2",
"caption":"hmm",
"user_id":"610bcc467b0c4008346547b8"
},
{
"_id": {"$oid":"610bce417b0c4008346547bd"},
"image":"myImage 3",
"caption":"..",
"user_id":"610bcc467b0c4008346547b8"
}
]
I want to join these two collections using $lookup. So I use the following aggregation on the users collection:
{
'$addFields': {
'userStrId': {
'$toString': '$_id'
}
}
}, {
'$lookup': {
'from': 'posts',
'localField': 'userStrId',
'foreignField': 'user_id',
'as': 'user_posts'
}
},
I used $addFields to add the _id field of the user as a string field, so I can use it in $lookup,
The following result is generated:
[
{
"_id":{"$oid":"610bcc467b0c4008346547b8"},
"name":"xyz",
"email":"xyz#gmail.com",
"password":"xyz",
"gender":"MALE",
"user_posts": [
{
"_id": {"$oid":"610bce417b0c4008346547bc"},
"image":"myImage 1",
"caption":"r/Mars",
"user_id":"610bcc467b0c4008346547b8"
},
{
"_id": {"$oid":"610bce417b0c4008346547be"},
"image":"myImage 2",
"caption":"hmm",
"user_id":"610bcc467b0c4008346547b8"
},
{
"_id": {"$oid":"610bce417b0c4008346547bd"},
"image":"myImage 3",
"caption":"..",
"user_id":"610bcc467b0c4008346547b8"
}
]
}
]
The question that I have right now is, how can I add a field to each of the documents in the user_posts such that I get the following result:
[
{
"_id":{"$oid":"610bcc467b0c4008346547b8"},
"name":"xyz",
"email":"xyz#gmail.com",
"password":"xyz",
"gender":"MALE",
"user_posts": [
{
"_id": {"$oid":"610bce417b0c4008346547bc"},
"image":"myImage 1",
"caption":"r/Mars",
"user_id":"610bcc467b0c4008346547b8",
"post_id":"610bce417b0c4008346547bc"
},
{
"_id": {"$oid":"610bce417b0c4008346547be"},
"image":"myImage 2",
"caption":"hmm",
"user_id":"610bcc467b0c4008346547b8",
"post_id": "610bce417b0c4008346547be"
},
{
"_id": {"$oid":"610bce417b0c4008346547bd"},
"image":"myImage 3",
"caption":"..",
"user_id":"610bcc467b0c4008346547b8",
"post_id":"610bce417b0c4008346547bd"
}
]
}
]
post_id added to each of the documents, and its value equal to the _id of that document converted to string.
You can add a stage at the end of your pipeline stages,
$map to iterate loop of user_posts
$mergeObjects to merge current object of user_posts and new fields user_id and post_id
{
$addFields: {
user_posts: {
$map: {
input: "$user_posts",
in: {
$mergeObjects: [
"$$this",
{
user_id: "$userStrId",
post_id: { $toString: "$$this._id" }
}
]
}
}
}
}
}
Playground

How to sum item in transaction subdocument mongodb from other document relationship

I'm new in mongodb and try small project and document are design just like below
products
[
{
_id:ObjectId('60d87d6fafd7a1377c03b2e6'),
productName:"noodles instant",
description:"lorem ipsum ... ... ...."
},
{
_id:ObjectId('60d87d6fafd7a1377c03b2e7'),
productName:"Sandal",
description:"lorem ipsum ... ... ...."
}
]
and my transaction document has structure is just like below
transactions
[
{
_id:ObjectId('60d8781031308dbf565eaaa8'),
trasactionSerial:"TRS20210000001",
transactionDate:2021-06-27T13:30:23.369+00:00,
productInTransactions:[
{
_id:ObjectId('60d8781031308dbf565eaab9'),
productId:ObjectId('60d87d6fafd7a1377c03b2e6'),
qty:1500
},
{
_id:ObjectId('60d8781031308dbf565eaa47'),
productId:ObjectId('60d87d6fafd7a1377c03b2e7'),
qty:200
}
]
},
{
_id:ObjectId('60d8781031308dbf565eaab7'),
trasactionSerial:"TRS20210000002",
transactionDate:2021-06-27T13:32:23.369+00:00,
productInTransactions:[
{
_id:ObjectId('60d8781031308dbf565eaab9'),
productId:ObjectId('60d87d6fafd7a1377c03b2e6'),
qty:100
},
{
_id:ObjectId('60d8781031308dbf565eaa47'),
productId:ObjectId('60d87d6fafd7a1377c03b2e7'),
qty:300
}
]
}
]
from the transaction I hope will get some result like below from the same date in transactionDate field
result
[
{
_id:ObjectId('60d87d6fafd7a1377c03b2e6'),
productName:"noodles instant",
qtyInTransaction:1600
},
{
_id:ObjectId('60d87d6fafd7a1377c03b2e7'),
productName:"Sandal",
qtyInTransaction:500
},
]
sorry maybe my English is poor to elaborate it
thanks for any feedback and your help
Use the $lookup stage which has $group in its pipeline option.
db.products.aggregate([
{
"$lookup": {
"from": "transactions",
"let": {
"pId": "$_id"
},
"pipeline": [
{
"$unwind": "$productInTransactions"
},
{
"$match": {
"$expr": {
"$eq": [
"$productInTransactions.productId",
"$$pId"
]
},
},
},
{
"$group": {
"_id": "$$pId",
"qtyInTransaction": {
"$sum": "$productInTransactions.qty"
}
},
},
],
"as": "matchedTransactions"
}
},
{
"$project": {
"_id": 1,
"description": 1,
"qtyInTransaction": {
"$arrayElemAt": [
"$matchedTransactions.qtyInTransaction",
0
]
}
},
},
])
Mongo Playground Sample Execution

How to match string from collection A with collection B in mongodb

I have collection A as
-> {"_id": .... , "data":"demon"}
-> {"_id": .... , "data":"god"}
collection B as
-> {"_id": .... , "title": "Book A", "description": "this book is about a demon."}
-> {"_id": .... , "title": "Book B", "description": "this book is about a god from Greek."}
-> {"_id": .... , "title": "Book C", "description": "this book is about a dog."}
I want to extract documents from collection B where description does not contain any text from collection A's "data" field.
in Plain JS, I want the following in Mongo Query
collectionA.filter( x => { return !collectionB.some(y => x.description.includes(y.data)});
How can I achieve this in MongoDB?
this would get the desired result i think but don't know how efficient it would be with a lot of data.
db.A.aggregate([
{
$project: {
_id: 0,
data: 1
}
},
{
$lookup:
{
from: 'B',
let: { word: '$data' },
pipeline: [
{
$match: {
$expr: {
$regexMatch: {
input: '$description',
regex: '$$word'
}
}
}
},
{
$project: { _id: 1 }
}
],
as: 'found'
}
},
{
$group: {
_id: null,
ids: {
$addToSet: {
$arrayElemAt: ['$found', 0]
}
}
}
},
{
$set: {
ids: {
$map: {
input: '$ids',
in: '$$this._id'
}
}
}
},
{
$lookup: {
from: 'B',
let: { found_ids: '$ids' },
pipeline: [
{
$match: {
$expr: {
$not: {
$in: ['$_id', '$$found_ids']
}
}
}
}
],
as: 'docs'
}
},
{
$unwind: '$docs'
},
{
$replaceWith: '$docs'
}
])
https://mongoplayground.net/p/YMrYeiUOQdo

getting error unknown group operator '$group' in mongoDB

I am trying to count distinct(not unique) or Emp No in same department.but getting error
query failed: unknown group operator '$group'
here is my code
https://mongoplayground.net/p/UvYF9NB7vZx
db.collection.aggregate([
{
$group: {
_id: "$Department",
total: {
"$group": {
_id: "$Emp No"
}
}
}
}
])
Expected output
[
{
"_id": "HUAWEI”,
“total”:1
},
{
"_id": "THBS”,
“total”:2
}
]
THBShave two different Emp No A10088P2C and A20088P2C
HUAWEI have only one Emp No A1016OBW
so, $group is Pipeline stage, you can only use it in upper level.
But for your required output there is lots of ways i believe,
we can do something like this as well:
db.collection.aggregate([
{
$group: {
_id: {
dept: "$Department",
emp: "$Emp No"
},
total: {
"$sum": 1
}
}
},
{
$group: {
_id: "$_id.dept",
total: {
"$sum": 1
}
}
}
])
Here, in first stage we are grouping with Department and its Emp No , and also we are having count of how many Emp No is in each dept.
[this count you can remove though as we are not using it.]
result of this stage will be:
[
{
"_id": {
"dept": "THBS",
"emp": "A10088P2C"
},
"total": 2
},
{
"_id": {
"dept": "THBS",
"emp": "A20088P2C"
},
"total": 1
},
{
"_id": {
"dept": "HUAWEI",
"emp": "A1016OBW"
},
"total": 3
}
]
next on top of this part data, i'm grouping again, with the dept. which comes in $_id.dept, and making count in the same way, which gives the result in your required format.
[
{
"_id": "HUAWEI",
"total": 1
},
{
"_id": "THBS",
"total": 2
}
]
Demo

Mongo - Aggregation of sum of values based on name

I'm attempting to perform an aggregate function to calculate the sum of the cost and margin values based on the name value. So if multiple results have the name "Fake Provider' I want the sum of the cost results and the sum of the margin results.
Query statement:
Pharmacy.aggregate([
{
$match: {
$and: [{ 'prescription.status': 'Ready for Pickup' }]
}
},
{
$project: {
'insurance.primary.name': 1,
'prescription.financial.cost': 1,
'prescription.financial.margin': 1
}
}
])
Results are similar to:
[
{
"_id": "5cab98cd293bd54e94c40461",
"insurance": {
"primary": {
"name": "Fake Provider 1"
}
},
"prescription": [
{
"financial": {
"cost": "2.89",
"margin": "5.60"
}
},
{
"financial": {
"cost": "0.88",
"margin": "1.24"
}
}
]
},
{
"_id": "5cab98d0293bd54e94c40470",
"insurance": {
"primary": {
"name": "Fake Provider 1"
}
},
"prescription": [
{
"financial": {
"cost": "3.22",
"margin": "9.94"
}
},
{
"financial": {
"cost": "2.57",
"margin": "9.29"
}
},
{
"financial": {
"cost": "2.03",
"margin": "10.17"
}
}
]
}
]
I have attempted to create a group statement without any luck. Also, the cost and margin values are currently stored as strings.
$group: {
_id: '$insurance.primary.name',
Financial: {
$push: {
id: '$insurance.primary.name',
name: '$insurance.primary.name',
cost: '$prescription.financial.cost',
margin: '$prescription.financial.margin'
}
}
}
I would like to get results similar to:
[
{
"primaryInsurance": "Fake Provider 1",
"totalFinancialCost": "11.59",
"totalFinancialMargin": "36.24"
},
{
"primaryInsurance": "Fake Provider 2",
"totalFinancialCost": "12.82",
"totalFinancialMargin": "22.16"
}
]
I think I have a solution that returns the results using a find and projection then using javascript to map thru the results and perform the addition. However, I would prefer to do this at the Database level.
You must first unwind the 'prescription' field then perform a group. Try this pipeline:
let pipeline = [
{
$unwind: {
path: '$prescription'
}
},
{
$group: {
_id: '$insurance.primary.name',
totalFinancialCost: {
$sum: { $convert: { input: '$prescription.financial.cost', to: "decimal" } }
},
totalFinancialMargin: {
$sum: { $convert: { input: '$prescription.financial.margin', to: "decimal" } }
}
}
}]
Notice how the values are converted to decimal in order to perform the sum.

Categories

Resources