mongodb: Trying to push a value in mongodb - javascript

I'm trying to $push a value in an array inside mongodb. This is the query:
db.user.update(
{ "_id": 5ac34a3c23f1b0343c155782 },
{ $push: { "courseId":5acd192a3ff62a287452891f}});
The first id, after _id is coming from a user model with this parameter, "_id" : ObjectId("5acb75a9e773ed2c10d5caa8").
The second id, after courseId is coming from this parameter "_id" : ObjectId("5acd192a3ff62a287452891f").
Desired user model should look like:
"_id" : ObjectId("5ac34a3c23f1b0343c155782"),
"tokens" : [ ],
"courseId" : [
"5ac37f5cd494e905b86c2433",
"<new id>"
],
Where am I going wrong?

db.user.update({ "_id": 5ac34a3c23f1b0343c155782 }, { $push: { "courseId":5acd192a3ff62a287452891f}})
You may need to use the "_id": ObjectId("5ac34a3c23f1b0343c155782") instead of just alphanumeric

See if following snippet works for you:
//following query will push to courseId
let modifier = {$push: { "courseId" :"5acd192a3ff62a287452891f"} };
let options = {returnOriginal: false};
db.collection('user').findOneAndUpdate({_id: ObjectId('5ac34a3c23f1b0343c155782')}, modifier, options)
.then(function(op) {
// see success or failure here in op
console.log(op);
})

Related

Find record in mongo $nin on array

I have a database (mongo) that stores posts and user separate. Within the posts schema I have an array. When a user marks a post as read, their user id is pushed into the array on the post schema. I'm then trying to display only the posts which their user id don't appear in the array.
Here is an example of my post structure.
{ "_id" : ObjectId("620eb60406b710c3ba2250f1"), "icon" : "fas fa-bullhorn", "title" : "Test Post", "scope" : true, "postedby" : "System", "postbody" : "Testing only content", "postcolour" : "orange", "posteddate" : "17/02/2022", "posthideuser" : [ "6205612355b2676a978b172b", "6203e917055a3558ffeb9fca" ] "__v" : 0 }
I tried using the following:
const posts = await Post.find({ posthideuser: { $nin: [user_id] } });
Which hasn't worked.
My Application is node, express/ejs. I will be happy to provide more information if required. Thanks in advance!
Your query seems to work as expected:
db.collection.find({
posthideuser: {
$nin: [
"test2"
]
}
})
playground
There was an issue with the structure as indicated.
await Post.findByIdAndUpdate(id, { $push: { posthideuser: [res.locals.user_id] } });
should be:
await Post.findByIdAndUpdate(id, { $push: { posthideuser: res.locals.user_id } });

MongoDB/Mongoose - Adding an object to an array of objects only if a certain field is unique

So I have a nested array of objects in my MongoDB document and I would like to add a new object to the array only if a certain field (in this case, eventId) is unique. My question is very similar to this post, only I cannot seem to get that solution to work in my case.
Here is what the documents (UserModel) look like:
{
"portal" : {
"events" : [
{
"important" : false,
"completed" : false,
"_id" : ObjectId("5c0c2a93bb49c91ef8de0b21"),
"eventId" : "5bec4a7361853025400ee9e9",
"user_notes" : "My event note"
},
...and so on
]
}
}
And here is my (so far unsuccessful) Mongoose operation:
UserModel.findByIdAndUpdate(
userId,
{ "portal.events.eventId": { $ne: req.body.eventId } },
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);
Basically I am trying to use '$ne' to check if the field is unique, and then '$addToSet' (or '$push', I believe they are functionally equivalent in this case) to add the new object.
Could anyone point me in the right direction?
Cheers,
Gabe
If you look into the documentation on your method you will see that the parameters passed are not in the proper order.
findByIdAndUpdate(id, update, options, callback)
I would use update instead and have your id and portal.events.eventId": { $ne: req.body.eventId } part of the initial filter followed by $addToSet: { "portal.events": req.body }
Something among these lines:
UserModel.update(
{
"_id": mongoose.Types.ObjectId(userId),
"portal.events.eventId": { $ne: req.body.eventId }
},
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);
You need to include your eventId check into condition part of your query. Because you're usig findByIdAndUpdate you can only pass single value matched against _id as a condition. Therefore you have to use findOneAndUpdate to specify custom filtering condition, try:
UserModel.findOneAndUpdate(
{ _id: userId, "portal.events.eventId": { $ne: req.body.eventId } },
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);

Mongoose: get the size of an array of objects with aggregate

I have a document in my collection:
{
"_id" : ObjectId("5b8aaaebf57de10e080c9151"),
"user_email" : "temp#temp.com",
"platforms_budget" : [
{
"_id" : ObjectId("5b8aaaebf57de10e080c9154"),
"platform_id" : "f_01",
"platform_name" : "Facebook"
},
{
"_id" : ObjectId("5b8aaaebf57de10e080c9153"),
"platform_id" : "i_01",
"platform_name" : "Instagram"
},
{
"_id" : ObjectId("5b8aaaebf57de10e080c9152"),
"platform_id" : "f_02",
"platform_name" : "Facebook_Adds"
}
],
"__v" : 0
}
I want to find specific user by "user_email" and get the length of the relevant "platform_budget" array. Which in this case suppose to be length=3.
My function is like this:
var BudgetSchema = require('../models/Budget');
router.post('/temp', async function (req, res) {
var length = await BudgetSchema.aggregate(
[{ $match: { user_email: "test#test.com" } }, { $unwind: "$platforms_budget" },
{ $project: { "platforms_budget.count": { $size: '$platforms_budget' } } }])
console.log(length);
})
When I try to console.log(length) I get an empty array.
I saw other answers on stackoverflow like this one, but I still can't understand what am I doing wrong or how to extract the size from the responce.
How do I get "platforms_budget" array size?
Thank you.
Assuming that ../models/Budget exports a Model, the Model#aggregate(Array, Function) expects the pipeline with aggregations as an array and an optional callback function that is passed an error (if any) and the result (if any).
.aggregate([...], function(error, resource) {
// do what you want here
});
Or what you can also do is use the Aggregate object itself and invoke .exec(Function) on it where the function is a callback as well.
.aggregate([...]).exec(function(error, resource) {
// do what you want here
});
I personally am still a bit confused about the documentation of .aggregate(Array, Function).
If a callback is passed, the aggregate is executed and a Promise is returned. If a callback is not passed, the aggregate itself is returned.
It sounds like if a callback is passed a promise is still returned but I couldn't find any evidence of any promise being returned by .aggregate(Array, Function) on GitHub at all.

Insert value inside array within Mongo DB documents using bulk write [duplicate]

I want to show products by ids (56e641d4864e5b780bb992c6 and 56e65504a323ee0812e511f2) and show price after subtracted by discount if available.
I can count the final price using aggregate, but this return all document in a collection, how to make it return only the matches ids
"_id" : ObjectId("56e641d4864e5b780bb992c6"),
"title" : "Keyboard",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
"_id" : ObjectId("56e65504a323ee0812e511f2"),
"title" : "Mouse",
"discount" : NumberInt(0),
"price" : NumberInt(1000)
"_id" : ObjectId("56d90714a48d2eb40cc601a5"),
"title" : "Speaker",
"discount" : NumberInt(10),
"price" : NumberInt(1000)
this is my query
productModel.aggregate([
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
and if i add this $in query, it returns empty array
productModel.aggregate([
{
$match: {_id: {$in: ids}}
},
{
$project: {
title : 1,
price: {
$cond: {
if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
}
}
}
}
], function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
Your ids variable will be constructed of "strings", and not ObjectId values.
Mongoose "autocasts" string values for ObjectId into their correct type in regular queries, but this does not happen in the aggregation pipeline, as in described in issue #1399.
Instead you must do the correct casting to type manually:
ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Then you can use them in your pipeline stage:
{ "$match": { "_id": { "$in": ids } } }
The reason is because aggregation pipelines "typically" alter the document structure, and therefore mongoose makes no presumption that the "schema" applies to the document in any given pipeline stage.
It is arguable that the "first" pipeline stage when it is a $match stage should do this, since indeed the document is not altered. But right now this is not how it happens.
Any values that may possibly be "strings" or at least not the correct BSON type need to be manually cast in order to match.
In the mongoose , it work fine with find({_id:'606c1ceb362b366a841171dc'})
But while using the aggregate function we have to use the mongoose object to convert the _id as object eg.
$match: { "_id": mongoose.Types.ObjectId("606c1ceb362b366a841171dc") }
This will work fine.
You can simply convert your id to
let id = mongoose.Types.ObjectId(req.query.id);
and then match
{ $match: { _id: id } },
instead of:
$match: { _id: "6230415bf48824667a417d56" }
use:
$match: { _id: ObjectId("6230415bf48824667a417d56") }
Use this
$match: { $in : [ {_id: mongoose.Types.ObjectId("56e641d4864e5b780bb992c6 ")}, {_id: mongoose.Types.ObjectId("56e65504a323ee0812e511f2")}] }
Because Mongoose autocasts string values for ObjectId into their correct type in regular queries, but this does not happen in the aggregation pipeline. So we need to define ObjectId cast in pipeline queries.

How to update array value in MongoDb

$set is overtiring complete array value how to update it
var obj = // contains some other data to update as well
obj.images=images; // updating obj with images []
Units.update({_id: 'id', {$set: obj});
finally my mongo object must be something like this
{
"_id" : "ZhBgrNFtr2LRPkQrZ",
"sitouts" : "test",
"interiors" : "test",
"features" : "test",
"keyHolder" : "test",
"images" : [
"1445481257465-8678-20130520_113154.jpg", ## `updated value ` ##
"1445481257456-3-20130520_113157.jpg",
"1445481258058-5771-20130520_113202.jpg",
"1445481258230-9603-20130521_075648.jpg"
]
}
https://docs.mongodb.org/manual/reference/operator/update/push/
$push, $each, $slice. See the documentation.
Here are a few ways to update the images array without overwriting it:
Update a Specific Index
Units.update({_id: id}, {$set: {'images.0': obj.images[0]}})
Append a Single Value
Units.update({_id: id}, {$push: {images: obj.images[0]}})
Append Multiple Values
Units.update({_id: id}, {$push: {images: {$each: obj.images}}})

Categories