MongoDB refuses to insert data - javascript

I have been trying to insert a piece of data in my db collection, mys chema looks like this
{
"_id": {
"$oid": "62d30157607575f6be6ce948"
},
"semester": "sem-5",
"subjectData": {
"subjectName": "eco",
"questionBank": [{
"question": "who are",
"answer": {
"introduction": "Hello my name is Izaan",
"features": ["tall", "handsome"],
"kinds": ["very", "kind"],
"conclusion": "Mighty man",
"_id": {
"$oid": "62d30157607575f6be6ce94b"
}
},
"_id": {
"$oid": "62d30157607575f6be6ce94a"
}
}],
"_id": {
"$oid": "62d30157607575f6be6ce949"
}
},
"__v": {
"$numberInt": "0"
}
}
And I would like to insert some questions and answers depending on semester and subject, first I want to query for the semester and then subject and then insert data without deleting prev data in the questionBank array
Here is how I am doing this and which is giving all kinds of error and still I have not managed to get the desired result
// IF DATA EXISTS UPDATE QUESTIONSBANK WITHOUT DELETING ANY ITEMS
try {
const result = await semesterData.update({
semester: {
$eq: semesterRecieved
},
subjectName: {
$eq: subject
},
}, {
$push: {
question: questionRecieved,
answer: answerRecieved2,
},
}, );
res.send(result);
} catch (error) {
console.log(error);
res.status(404).send(error.message);
}
}

Related

Update multiple or single object in an array with specified data from request

I am not great with MongoDB's advanced techniques.
My record in the MongoDB collection:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Member",
},
{
"_user": ObjectId("3"),
"role": "Member",
}
],
}
Node.js / ExpressJS
I created API to update the array like below but did not work.
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
try {
const project = await Project.updateMany(
{ _id: req.params.projectID },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
I use the API parameter to get the project ID. Here is the request body data:
{
userID : ["2","3"];
role: "Admin"
}
So the API will get an array of userID to match and set all "role" fields to "Admin" to all matched.
I wanted the data to be like this:
{
"_id": ObjectId("1"),
"manager": ObjectId("12345"),
"code": "PS",
"title": "Performance System",
"users": [
{
"_user": ObjectId("1"),
"role": "Member",
},
{
"_user": ObjectId("2"),
"role": "Admin",
},
{
"_user": ObjectId("3"),
"role": "Admin",
}
],
}
Am I doing the right practice? If it is bad practice, what is the best way to solve this?
The query is fine. Just make sure that you pass the value with the exact type as in the MongoDB document.
var mongoose = require('mongoose');
const updateProjectMember = asyncHandler(async (req, res) => {
const { userID, role } = req.body.userData;
userID = userID.map(x => mongoose.Types.ObjectId(x));
try {
const project = await Project.updateMany(
{ _id: mongoose.Types.ObjectId(req.params.projectID) },
{ $set: { "users.$[selectedUser].role": role } },
{ arrayFilters: { "selectedUser._user": { $in: userID } } }
);
res.status(200).json(project);
} catch (error) {
res.status(400);
throw new Error(error);
}
}

Find all n days documents in MongoDB

I've been looking to get data for the last n days. For example, I want to just all the data of the last 3 days. After implementing a solution from another question in StackOverflow I'm not getting all the documents. I am only getting one document. If I want to see the documents for the last 3 days it is only showing data for one particular day.
Here's my Schema:
dayWiseClicks: [
{
date: {
type: Date,
},
dailyClicks: {
type: Number,
default: 0,
},
},
],
Here's the data I have before performing the query:
{
"_id": {
"$oid": "61eff4bacf8335c7013f8065"
},
"dayWiseClicks": [
{
"dailyClicks": 3,
"_id": {
"$oid": "61eff5db5dca56cae4530db2"
},
"date": {
"$date": "2022-01-24T18:00:00.000Z"
}
},
{
"dailyClicks": 4,
"_id": {
"$oid": "61eff60b5dca56cae4530db6"
},
"date": {
"$date": "2022-01-25T18:00:00.000Z"
}
},
{
"dailyClicks": 2,
"_id": {
"$oid": "61eff64a5dca56cae4530dba"
},
"date": {
"$date": "2022-01-26T18:00:00.000Z"
}
},
{
"dailyClicks": 7,
"_id": {
"$oid": "61f60ce51f14b01f8f5be936"
},
"date": {
"$date": "2022-01-29T18:00:00.000Z"
}
},
{
"dailyClicks": 11,
"_id": {
"$oid": "61f7b1d3931b0f8bc33703d4"
},
"date": {
"$date": "2022-01-30T18:00:00.000Z"
}
},
{
"dailyClicks": 8,
"_id": {
"$oid": "61f8bdf63cc3a51b72474cb9"
},
"date": {
"$date": "2022-01-31T18:00:00.000Z"
}
},
{
"dailyClicks": 7,
"_id": {
"$oid": "61fba7159692624ce8ea04d6"
},
"date": {
"$date": "2022-02-02T18:00:00.000Z"
}
}
],
}
In theory, if I want to see the last 3 days of data. It should be showing data of 31st Jan, 2nd February but It is only showing Data of 31st January.
Here's the data I am getting:
{
"message": "Url By ID",
"result": {
"_id": "61eff4bacf8335c7013f8065",
"dayWiseClicks": [
{
"dailyClicks": 8,
"_id": "61f8bdf63cc3a51b72474cb9",
"date": "2022-01-31T18:00:00.000Z"
}
]
}
}
Here's my Code:
exports.lastNDays = async (req, res) => {
try {
const url = await URL.findById(
{ _id: req.params.id },
{
dayWiseClicks: {
$elemMatch: {
date: {
$gte: moment().add(-3, "days"),
},
},
},
}
)
return res.status(200).json({
message: "Url By ID",
result: url,
});
} catch (error) {
return res.status(404).json({ error: error.message });
}
};
Can any one tell me exactly where I am making the mistake?
The aggregation->$filter option seems more suitable for the task , example:
db.collection.aggregate([{
$match: {
"_id": {
"$oid": "61eff4bacf8335c7013f8065"
}
}
},
{
$project: {
dayWiseClicks: {
$filter: {
input: "$dayWiseClicks",
as: "item",
cond: {
$gte: [
"$$item.date",
{
"$date": "2022-01-30T18:00:00.000Z"
}
]
}
}
}
}
}
])
Explained:
$match single document by _id
$filter only the dayWiseClicks greater or equal to certain date.
playground
If your dayWiseClicks are in natural date-ascending order (and it seems that way), then to generically capture the last 3 days of any sequence of dates can be done with $slice:
db.foo.aggregate([
{$addFields: {dayWiseClicks: {$slice: ["$dayWiseClicks", -3]}}}
]);
You can prepend $match stages as detailed in previous answers.
NOTE: Coming up in v5.4 (available now in 5.2 rapid release for MongoDB Atlas) is the long-awaited sortArray operator. If the dayWiseClicks was not in date order, then making it that way and finding the last 3 dates is freshingly simple:
db.foo.aggregate([
{$addFields: {dayWiseClicks: {$slice: [{$sortArray:{input: "$dayWiseClicks", sortBy: {"date":1}}, -3]}}}
]);
Similarly, to get the last 3 dates but in descending order:
db.foo.aggregate([
{$addFields: {dayWiseClicks: {$slice: [{$sortArray:{input: "$dayWiseClicks", sortBy: {"date":-1}}, 3]}}}
]);

Remove particular object from array in mongoose document (Mongodb)

I have to remove one element from array in document 'dsrNote'
which has "_id" : ObjectId("58a5594bb77d2f1dd49e2986")
{
"_id": ObjectId("58a558efb77d2f1dd49e2983"),
"userId": ObjectId("586356b199248d1517a6758b"),
"dsrNote": [
{
"activity": "ajay kumar dogra",
"_id": ObjectId("58a5594bb77d2f1dd49e2986")
},
{
"activity": "ajay kumar",
"_id": ObjectId("58a55969b77d2f1dd49e2987")
}
],
}
In above document i need to remove first object from dsrNote array
i have tried this, but it is not working
collectionName.update({ "userId": "586356b199248d1517a6758b" }, { $pull: { "dsrNote": { "_id": "58a5594bb77d2f1dd49e2986" } } }).exec(function (err, data) {});
You can try this it is working on my case
DSR.update({"userId":req.ID,"dsrNote._id":req.params.id}, { $pull: {"dsrNote": { "_id":req.params.id}}})
.exec(function(err,data){
});

Aggregate match pipeline not equal to in MongoDB

I am working on an aggregate pipeline for MongoDB, and I am trying to retrieve items where the user is not equal to a variable.
For some reason, I couldn't make it work. I tried to use $not, $ne and $nin in different possible way but can't make it to work.
This is how it looks like:
Data sample:
[{
"_id": { "$oid": "565674e2e4b030fba33d8fdc" },
"user": { "$oid": "565674832b85ce78732b7529" }
}, {
"_id": { "$oid": "565674e2e4b030fba33d8fdc" },
"user": { "$oid": "565674832b85ce78732b7529" }
}, {
"_id": { "$oid": "565674e2e4b030fba33d8fdc" },
"user": { "$oid": "56f9dfc5cc03ec883f7675d0" }
}]
Pipeline sample (simplified for this question):
Where req.query.user.id = "565674832b85ce78732b7529"
collection.aggregate([
{
$match: {
user: {
$nin: [ req.query.user.id ],
}
}
}
]
This should return only the last item.
Do you have any idea how to retrieve the data that doesn't match the user?
Thanks
Edit:
The following doesn't work either:
collection.aggregate([
{
$match: {
'user.$oid': {
$nin: [ req.query.user.id ],
}
}
}
]);
I also tried with ObjectID() and mongodb complains: [MongoError: Argument must be a string]
var ObjectID = require('mongodb').ObjectID;
// Waterline syntax here
MyCollection.native(function (err, collection) {
collection.aggregate([
{
$match: {
'user': {
$nin: [ ObjectID(req.query.user.id) ],
}
}
}
], function (err, result) {
console.log(err, result);
});
});
But this line works in the shell:
db.collection.aggregate([{$match:{"user":{"$nin":[ObjectId("565674832b85ce78732b7529")]}}}])
Based on the answer here, you can change
var ObjectId = require('mongodb'). ObjectID;
to
var ObjectId = require('sails-mongo/node_modules/mongodb').ObjectID;

update matched records from another collection?

Can someone please help me update a collection based on another? I have a pickups collection like so.
{
"_id": {
"$oid": "53a46be700b94521574b6f75"
},
"created": {
"$date": 1403236800000
},
"receivers": [
{
"model": "somemodel1",
"serial": "someserial1",
"access": "someaccess1"
},
{
"model": "somemodel2",
"serial": "someserial2",
"access": "someaccess2"
},
{
"model": "somemodel3",
"serial": "someserial3",
"access": "someaccess3"
}
],
"__v": 0
}
I would like to iterate through the receivers array and search each access in another collection and if found add the activity it was found in.
Here is the workorders collection I want to search in.
{
"_id": {
"$oid": "53af72481b2aeade0b46d025"
},
"activityNumber": "someactivity",
"date": "06/28/2014",
"lines": [
{
"Line #": "1",
"Access Card #": "someaccess1"
},
{
"Line #": "2",
"Access Card #": "someaccess2"
},
{
"Line #": "3",
"Access Card #": "someacess3"
}
],
}
And this is what I would like to end up with.
{
"_id": {
"$oid": "53a46be700b94521574b6f75"
},
"created": {
"$date": 1403236800000
},
"receivers": [
{
"model": "somemodel1",
"serial": "someserial1",
"access": "someaccess1",
"activityNumber": "someactivity"
},
{
"model": "somemodel2",
"serial": "someserial2",
"access": "someaccess2",
"activityNumber": "someactivity"
},
{
"model": "somemodel3",
"serial": "someserial3",
"access": "someaccess3",
"activityNumber": "someactivity"
}
],
"__v": 0
}
I have created an array containing all the access from pickups.
var prodValues = db.pickups.aggregate([
{ "$unwind":"$receivers" },
{ "$group": {
"_id": null,
"products": { "$addToSet": "$receivers.access"}
}}
])
I can easily iterate through the array and search the workorders colleciton and return the activity these are used in. But I'm not sure how to perform a find and update the pickups collection when found.
db.workorders.find({ "lines.Access Card #": { "$in": prodValues.result[0].products }},{activityNumber:1})
Thank you for your help.
Really I would loop this in the completely opposite order as that should be more efficient:
var result = db.workorders.aggregate([
{ "$project": {
"activityNumber": 1,
"access": "$lines.Access Card #",
}}
]).result;
result.forEach(function(res) {
res.access.forEach(function(acc) {
db.pickups.update(
{ "receivers.access": acc },
{ "$set": { "receivers.$.activityNumber": res.activityNumber } }
);
});
});
With MongDB 2.6 you can clean this up a bit with a cursor on the aggregate output and the use of the bulk operations API:
var batch = db.pickups.initializeOrderedBulkOp();
var counter = 0;
db.workorders.aggregate([
{ "$project": {
"activityNumber": 1,
"access": "$lines.Access Card #",
}}
]).forEach(function(res) {
res.access.forEach(function(acc) {
batch.find({ "receivers.access": acc }).updateOne(
{ "$set": { "receivers.$.activityNumber": res.activityNumber } }
);
});
if ( counter % 500 == 0 ) {
batch.execute();
var batch = db.pickups.initializeOrderedBulkOp();
counter = 0;
}
});
if ( counter > 0 )
batch.execute();
Either way, you are basically matching the document and the position of the array on the values of "access" returned from the first aggregation query, and in the current line. This allows the update of the related information at the specified position.
The MongoDB 2.6 improvements are that you are not pulling all the results out of the "workoders" collection into memory as an array, so only each document is pulled in from the the cursor results.
The Bulk operations actions store the "updates" in manageable blocks that should fall under the 16MB BSON limit and then you send this in those blocks instead of individual updates. The driver implementation should handle most of this, but there is some "self management" added in just to be safe.

Categories

Resources