How to user inner query with mongoDB update operation? - mongodb

i'm trying to write an update query to update a column/filed of a collection. My collection has 4 fields: _id, name, date1, date2.
I'm trying to write an update query to set date1 = date2 and i tried using inner query as shown below but didn't work.
db.myCollection.updateMany(
{},
{
'$set':
{
'date2': db.myCollection.find({},{date1:1, _id:0}).limit(1)
}
}
);

Maybe something like this( version 4.2+):
db.collection.update({},
[
{
$addFields: {
date1: "$date2"
}
}
],
{
multi: true
})
playground
For your case ( Version 3.6 ):
db.collection.find().forEach(
function (elem) {
db.collection.update(
{
_id: elem._id
},
{
$set: {
date1: elem.date2
}
}
);
}
);

var cursor = db.collection.find()
var requests = [];
cursor.forEach(document => {
requests.push( {
'updateOne': {
'filter': { '_id': document._id },
'update': { '$set': { 'date1': document.date2 } }
}
});
if (requests.length === 500) {
//Execute per 500 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.collection.bulkWrite(requests);
}

Related

Statistics with Mongo DB

I have the following DB structure :
{
"uploadedAt": "2021-09-22T22:09:12.133Z",
"paidAt: "2021-09-30T22:09:12.133Z",
"amount": {
"currency": "EUR",
"expected": 70253,
"paid": 0
},
}
I would like to know how do I calculate the total amount that still need to be paid (expected - paid), and the average date between uploadedAt and paidAt. This for multiple records.
My function for getting the data is (the criteria should be updated to get this data).
const invoiceParams = new FindParams();
invoiceParams.criteria = { company: company._id }
const invoices = await this.findAll(invoiceParams);
FindAll function looks like:
async findAll(
params: FindParams,
ability?: Ability,
includeDeleted: boolean = false,
): Promise<Entity[]> {
let queryCriteria: Criteria = params.criteria;
let query: DocumentQuery<Entity[], Entity> = null;
if (!includeDeleted) {
queryCriteria = {
...queryCriteria,
deleted: { $ne: true },
};
}
try {
if (ability) {
ability.throwUnlessCan('read', this.entityModel.modelName);
queryCriteria = {
...toMongoQuery(ability, this.entityModel.modelName),
...queryCriteria,
};
}
query = this.entityModel.find(queryCriteria);
if (params.populate) {
query = query.populate(params.populate);
}
if (params.sort) {
query = query.sort(params.sort);
}
if (params.select) {
query = query.select(params.select);
}
return query.exec();
} catch (error) {
if (error instanceof ForbiddenError) {
throw new ForbiddenException(error.message);
}
throw error;
}
}
Update:
const paymentTime = await this.invoiceModel.aggregate([
{
$group: {
_id: "$account",
averageSpread: { $avg: { $subtract: ["$paidAt", "$uploadedAt"] } },
count: { $sum: 1 }
}
}
]);
Try this aggregation pipeline:
db.invoiceParams.aggregate([
{
$set: {
expectedPaid: { $subtract: ["$amount.expected", "$amount.paid"] },
averageDate: { $toDate: { $avg: [{ $toLong: "$uploadedAt" }, { $toLong: "$paidAt" }] } }
}
}
])

mongoose - update many from an array of Ids

im trying to update all keys ('indexOrder') in an array of objects in a document.
The values for the update are recived as an array from the client:
[{_id:'1s284hd72hdd', indexOrder: 1}, {_id:'543543531', indexOrder: 2}, etc..]
im trying to match the _id of the array from the client with the _id of the objects in the document. When a match is found -> it needs to update the 'indexOrder' in the document to its value from the array from the client.
currently im doing it with looping on the client array, and updating for each iteration.
async updateIndexOrder(orderList) {
try {
orderList.forEach(async ({_id, indexOrder}) => {
await Model.findOneAndUpdate({_id}, {$set:{indexOrder}})
})
return true;
} catch (err) {
throw new Error(err);
}
}
How can I update in one call instead of so many server calls?
something like:
async updateIndexOrder(orderList) {
const idList= orderList.map(x => x._id)
try {
await Model.updatMany(
{_id: {$in:{idList}},
{$set: {indexOrder: orderList[FIND INDEX OF THE ITERATING _id].indexOrder}}
)
} catch (err) {
throw new Error(err);
}
}
Thank you.
you can do it in mongodb 4.2 and onwards
exports.updateDIndexOrder = async (keyValPairArr) => {
try {
let data = await Model.collection.update(
{ _id: { $in: keyValPairArr.map(o => o._id) } },
[{
$set: {
indexOrder: {
$let: {
vars: { obj: { $arrayElemAt: [{ $filter: { input: keyValPairArr, as: "kvpa", cond: { $eq: ["$$kvpa.id", "$_id"] } } }, 0] } },
in: "$$obj.indexOrder"
}
}
}
}],
{ runValidators: true, multi: true }
)
return data;
} catch (error) {
throw error;
}
}

Can Update document with mongodb query but not work when do in mongoose [duplicate]

This question already has answers here:
Update nested subdocuments in MongoDB with arrayFilters
(2 answers)
Closed 3 years ago.
My collection is like this: https://mongoplayground.net/p/91InBXrUq7R
With this query I can update replies.likes
db.getCollection("posts").updateOne(
{
"_id": ObjectId("5da832caeb173112348e509b"), //posts._id
"comments.replies._id":ObjectId("5db6a88f7c6cfb0d0c2b689b"),//replies._id
},
{ "$push": { "comments.$[outer].replies.$[inner].likes": "10000012" } },
{
"arrayFilters": [
{ "outer._id": ObjectId("5db06e11d0987d0aa2cd5593") },//comments._id
{ "inner._id": ObjectId("5db6a88f7c6cfb0d0c2b689b") }//replies._id
]
}
)
But when I code using mongoose, express, collection not update
//Like Reply toggle
router.post("/toggleLikeReply", function(req, res, next) {
var id_post = req.body.id_post;
var id_comment = req.body.id_comment;
var id_reply = req.body.id_reply;
var id_user = req.user._id;
console.log("id_post: "+id_post+" id_comment: "+id_comment+" id_reply: "+id_reply+" id_user: "+id_user);
//todo
Post.aggregate([
{ $match: {_id: ObjectId(id_post),"comments._id": ObjectId(id_comment)}},
{ $unwind: "$comments"},
{ $match: { "comments._id": ObjectId(id_comment)}},
{ $project: {"replies": "$comments.replies", _id: 0}},
{ $match: { "replies._id": ObjectId(id_reply)}},
{ $project: {"likes": "$replies.likes", _id: 0}},
]).exec((err, users_liked) => {
var index = users_liked[0].likes[0].indexOf(id_user);
console.log(users_liked[0].likes[0]);
//todo
if (index == -1) {
const updatePost = async () => {
try {
await Post.updateOne({
_id: ObjectId(req.body.id_post),
"comments.replies._id": ObjectId(req.body.id_reply)},
{ $push: {"comments.$[outer].replies.$[inner].likes": ObjectId(req.user._id)} },
{
"arrayFilters": [
{ "outer._id": ObjectId(req.body.id_comment) },
{ "inner._id": ObjectId(req.body.id_reply) }
]
}
);
} catch (error) {
console.log("error", error);
}
};
updatePost().then(function(data) {res.send({ like: true, success: true})});
}else{
const updatePost = async () => {
try {
await Post.updateOne({
_id: ObjectId(req.body.id_post),
"comments.replies._id": ObjectId(req.body.id_reply)},
{ $pull: {"comments.$[outer].replies.$[inner].likes": ObjectId(req.user._id)} },
{
"arrayFilters": [
{ "outer._id": ObjectId(req.body.id_comment) },
{ "inner._id": ObjectId(req.body.id_reply) }
]
}
);
} catch (error) {
console.log("💥", error);
}
};
updatePost().then(function(data) {res.send({ like: false, success: true})});
}
})
});
I logged the all the id is come and the same as I did with mongo query directly .
id_post: 5da832caeb173112348e509b
id_comment: 5db06e11d0987d0aa2cd5593
id_reply: 5db6a88f7c6cfb0d0c2b689b
id_user: 5da85558886aee13e4e7f044
What is wrong with my code using mongoose and express?
Try This Query
var mongoose = require('mongoose');
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId
const updatePost = async () => {
try {
await Post.updateOne({
_id: ObjectId(req.body.id_post),
"comments.replies._id": ObjectId(req.body.id_reply)},
{ $push: {"comments.$[outer].replies.$[inner].likes": req.user._id} },
{
"arrayFilters": [
{ "outer._id": ObjectId(req.body.id_comment) },
{ "inner._id": ObjectId(req.body.id_reply) }
]
}
);
} catch (error) {
console.log("error", error);
}
};
updatePost().then(function(data) {res.send({ like: true, success: true})});

MongoDB + Mongoose Aggregate w/ Asnyc

I've got the following route in my express file, which takes parameters passed in from a middleware function and queries my backend MongoDB database. But for some reason, it only ever returns an empty array.
I'd like to convert the Mongoose model that allows me to use aggregate functions into async/await to conform with the rest of my code. It's online here.
module.exports = {
search: asyncWrapper(async(req, res, next) => { // Retrieve and return documents from the database.
const {
filterTarget,
filter,
source,
minDate,
maxDate,
skip,
limit,
sortBy,
sortOrder
} = req.search;
try {
const mongoData = await Model.aggregate([
{
$match: {
date: {
$gt: minDate, // Filter out by time frame...
$lt: maxDate
}
}
},
{
$match: {
[filterTarget]: filter // Match search query....
}
},
{
$set: {
[filterTarget]: { $toLower: `$${filterTarget}` } // Necessary to ensure that sort works properly...
}
},
{
$sort: {
[sortBy]: sortOrder // Sort by date...
}
},
{
$group: {
_id: null,
data: { $push: "$$ROOT" }, // Push each document into the data array.
count: { $sum: 1 }
}
},
{
$project: {
_id: 0,
count: 1,
data: {
$slice: ["$data", skip, limit]
},
}
}
])
return res.status(200).json({ data: mongoData.data || [], count: mongoData.count || 0 });
} catch (err) {
next(err);
}
})
};
For some reason, the route is only returning an empty array every time. I've double and triple checked my variables, they are not the problem.
How can I use the Mongoose.aggregate() function in an async await route?

Building MongoDB query with conditions

I need to build a MongoDB query by pushing a new language if it does not exist in the array already. But if it exists I get an error this '$push' is empty. It is correct.
My question is how to build the query adding $push only when it is necessary?
let pushNewLanguage = {};
if (!profile.languages || (profile.languages && !profile.languages.find(l => l === languageId))) {
pushNewLanguage = { languages: languageId };
}
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
{
$inc: { countPublishedPoems: 1 },
$push: pushNewLanguage
}
);
Remove the conditional logic and use $addtoSet instead of $push.
$addToSet will only add the item if it doesn’t exist already.
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
{
$inc: { countPublishedPoems: 1 },
$addToSet: { languages: languageId }
}
);
Since you are writing Javascript, you can create a "base" update object, and then add the $push property if you need:
const update = {
$inc: { countPublishedPoems: 1 }
}
if (!profile.languages || (profile.languages && !profile.languages.find(l => l === languageId))) {
update["$push"] = { languages: languageId };
}
const profileUpdate = await
Profiles.rawCollection().update(
{ userId: this.userId },
update
);