Collection field showing undefined when aggregate is used in MongoDB - node.js

I'm trying to concat two arrays with aggregate. However, output is showing Cannot read properties of undefined (reading 'allAddresses'). And wanted to implement in EJS. How can I achieve that? There is a code below:
app.post('/indexReplaced.html', (req, res) => {
Address.find({}, function(err, item){
const response = Address.aggregate([
{
$group: {
_id: null,
addresses: {
$push: "$addresses"
}
}
},
{
$project: {
allAddresses: {
$reduce: {
input: "$addresses",
initialValue: [],
in: {
"$concatArrays": [
"$$value",
"$$this"
]
}
}
}
}
}
]);
const allAddresses = response[0]["allAddresses"];
res.render("indexCalculated", {
address: item,
allAddresses: allAddresses
})
})
});
P.S: Tried to nest aggregate pipeline into Address.find() to render the collection as well. I hope it doesn't affect the pipelane.

Related

Update nested object in array MongoDB

I need to find and update documents with category that corresponding to the query. Array could contain mo than one corresponding id.
Query:
{
"ids": ["61f1cda47018c60012b3dd01", "61f1cdb87018c60012b3dd07"],
"userId": "61eab3e57018c60012b3db3f"
}
I got collection with documents like:
`{
"_id":{"$oid":"61f1cdd07018c60012b3dd09"},
"expenses":[
{"category":"61eafc104b88e154caa58616","price":"1111.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"2222.00"},
{"category":"61f1cda47018c60012b3dd01","price":"1241.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"111.00"}
],
"userId":"61eab3e57018c60012b3db3f"
}`
my method:
async myMethod(ids: [string], userId: string) {
try {
const { ok } = await this.ExpensesModel.updateMany(
{"userId": userId, "expenses.category": { $in: ids }},
{$set: {"expenses.$.category": "newCategoryID"}}
);
return ok
} ........
I path array of ids ["61f1cda47018c60012b3dd01","61f1cdb87018c60012b3dd07","61f1cdb87018c60012b3dd07"] and userId, this code update only 1 category by document.
So can i made it with mongo build in methods? or i need to find matching document and update it it by my self and after that update or insert;
Update with arrayFilters
db.collection.update({
"expenses.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
},
{
$set: {
"expenses.$[elem].category": "61eab3e57018c60012b3db3f"
}
},
{
arrayFilters: [
{
"elem.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
}
]
})
mongoplayground

MongoDB Node.js aggregation too slow for function

i hope this question is not answered too many times.
However my problem is that i need to extract objects from an array inside a document.
The way i have solved this is with the aggregation pipeline builder integrated in MongoDB, with this i get the correct result.
But when i implemented this in the API i am building the data does not return with the request. So i suspect the operation is too slow or something along those lines.
My code looks like this:
const searchIngredientInInventory = async (req: Request, res: Response) => {
const dbConn = await getDb();
const aggDoc = [
{
'$match': {
'type': {
'$ne': 'shoppingList'
}
}
}, {
'$unwind': {
'path': '$container'
}
}
]
dbConn.collection(coll).aggregate(aggDoc).toArray((err, result) => {
if (err) {
res.status(400).send(err);
console.log(err)
} else {
res.status(200).send(result);
}
})
}
And the database has this structure:
Cluster
Database
Collection
Doc1
Array with objects
Doc2
Array with objects
The collection is not large, its 5 documents and 36 kilobytes.
The return i get is empty array: []
Does anybody have any idea what i am doing wrong?
The problem was in the aggregation document, or at least the problem stopped occurring when I updated it.
The new aggregation document looks like this now:
const aggDoc = [
{
'$match': {
'type': {
'$ne': 'shoppingList'
}
}
}, {
'$unwind': {
'path': '$container'
}
}, {
'$project': {
'item': '$container.item',
'expirationDate': '$container.expirationDate'
}
}, {
'$match': {
'item': {
'$regex': ingredient
}
}
}
]

Push to array in Mongodb

How do I push to the inner arrays in MongoDB?
[
{ emoji1: ['user19', 'user20', 'user21']},
{ emoji5: ['user12', 'user13', 'user14']},
{ emoji9: ['user29', 'user30', 'user34']}
]
I tried:
await Post
.updateOne({ _id: postID }, {
$push: {
[`reactions[0].emoji1`]: 'random user'
}
})
...where Post is my Mongoose Schema and "reactions" is the array above. I think I am doing something wrong in $push.
The result should be:
[
{ emoji1: ['user19', 'user20', 'user21', 'random user']},
{ emoji5: ['user12', 'user13', 'user14']},
{ emoji9: ['user29', 'user30', 'user34']}
]
You can use this query:
db.collection.update({
id: 1,
"reactions.emoji1": {
"$exists": true
}
},
{
"$push": {
"reactions.$.emoji1": "random user"
}
})
Example here

check an array of string value with array of object in mongodb

I have array of strings like this
let fromHour = ['2.5','3','3.5']
let toHour = ['2.5','3','3.5']
I have an array of object saved in mongoDB
timeRange = [
{
from:'2.5',
to:'3'
},
{
from:'3',
to:'3.5'
}
]
I want to check if any of my array of string value exist in that object value
I have tried this but it give me this error ( Unrecognized expression '$match' )
checkAppoint = await Appointment.aggregate([
{
$project: {
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange: {
'$match': {
'from': { $in: fromHolder },
'to': { $in: toHolder },
},
},
},
},
]);
also I have tried this solution and it work for me but it take to much time so I am trying this with aggregate
checkAppoint = await Appointment.findOne({
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange:{$elemMatch:{
from:{$in:fromHolder},
to:{$in:toHolder}
}}
});
So anyone have a solution for that
Just try $elemMatch and $in operators,
using find() method
checkAppoint = await Appointment.find({
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
})
Playground
using aggregate() method
checkAppoint = await Appointment.aggregate([
{
$match: {
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
}
}
])
Playground
So I have found a way around to solve this problem and I will share the solution I used
First I want to minimize my request to mongodb so I am now making just one request that bring all the appointment with the required date
and I want to make it this way because my fromHour and toHour array will change many time through single request
helperArray => contains all the day I want to check it's range
let checkAppoint = await Appointment.find({
date: { $in: helperArray },
status: { $in: ['pending', 'on-going'] },
});
now inside my for loop I will go through that data
checkAppoint.filter((singleAppoint) => {
if (singleAppoint._doc.date === myScheduleFinal[k].date) {
singleAppoint._doc.timeRange.map((singleTime) => {
if (fromHolder.includes(singleTime.from)) {
busy = true;
}
});
}
});

Mongoose findbyIdAndUpdate - how to update one field using sum from another array field

So this is how my document looks like
"donator": [
{
"_id": "5edbd7d182af1f5aceab62bb",
"donatorName": "Niki",
"donationValue": 5000000
},
{
"_id": "5edbd7d182af1f5aceab62bc",
"donatorName": "Brian",
"donationValue": 5000000
}
],
"currentValue" : 1000000
I get my currentValue from donationValue sum in donator array :
donator.reduce((a, { donationValue }) => a + donationValue,0);
and I want to update the document by adding new object in donator array, and automatically updates currentValue field when the data updated.
I tried using aggregate
MyCollection.findByIdAndUpdate(id, [
{
$set: req.body,
$set: { currentValue: { $sum: { $sum: donator.donationValue } } },
},
]);
It's a good practice to sanitise your input and not directly use req.body.
so let's say
const donator = sanitizeDonator(req.body)
Then you can add donator and update currentValue as follows.
Note that _id on donator won't be auto generated by the update query, so it has to be present in the donator object.
MyCollection.findByIdAndUpdate(id, [
{
$set: {
donator: {
$concatArrays: ["$donator", [donator]] // adding donator to the last element
}
}
}, {
$set: {
currentValue: {
$reduce: {
initialValue: 0,
input: "$donator",
in: {
$add: ["$$this.donationValue", "$$value"]
}
}
}
}
}
]);
Relevant APIs
$concatArrays,
$reduce

Resources