I am using this command to update the document.
order = await db.collection("orders").findOneAndUpdate({ order_id: req.body.ORDERID }, {$set: { payment_status: "Paid", paymentInfo: JSON.stringify(myrequest) }})
console.log(order)
But the document is not updated instead return this in console
lastErrorObject: { n: 0, updatedExisting: false },
value: null,
ok: 1,
'$clusterTime': {
clusterTime: new Timestamp({ t: 1663565745, i: 13 }),
signature: {
hash: new Binary(Buffer.from("5165sd1vdsvds651vds5vvs5dvdsvdskvjdsv, "hex"), 0),
keyId: new Long("1451151132154123165")
}
To update the Document Using MongoDB two conditions are required filter and update information.
const myquery = { orderId: req.body.ORDER_ID };
const newvalues = { $set: { payment_status: "Paid", paymentInfo: JSON.stringify('your Payment Info in JSON format') }};
await db.collection("orders").updateOne(myquery, newvalues);
Please go through the Document for detailed Information
Related
I have a controller where I am trying to query the most popular posts within the last week, sorted by most popular, and has a max cap of 50 posts. I am trying to use the aggregate() method; however, I am not sure if I am doing it correctly. When I run the query In insomnia I get an error like so:
{
"ok": 0,
"code": 8000,
"codeName": "AtlasError"
}
Here is my post model:
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
message: {
type: String,
required: true
},
//replace creator with name
name: String,
creator: String,
tags: [String],
size: String,
selectedFile: String,
likes: {
type: [String],
default: [],
},
comments: {
type: [String],
default: []
},
createdAt: {
type: Date,
default: new Date(),
},
dogTreats: {
type: Number,
default: 0,
required: false,
}
});
and here is my controller/post.js
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate()-7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([{"$sort": { likes: -1}}, { "$limit": 50}, { "$gt": currentTime }])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
You can use find method. It is better to use here.
If you need to reach a value from another table populated, aggregation is better to use. However, at here, find is the best way to reach datas.
const mostPopular = await PostMessage.find({createdAt: {$gt : currentTime}}).sort({likes: -1}).limit(50)
Try this aggregation
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate() - 7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([
{ $match: { createdAt: { $gt: currentTime } } },
{ $sort: { likes: -1 } },
{ $limit: 50 }
])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
I am trying to check if there is an existing conversation between two users before creating another one.
My Conversation object stores the conversation participants in an array, I need to return a conversation object that has BOTH participants (senderId & recId) that exists in my database but I am unable to build to correct MongoDB query to get it.
Please see the queries I have tried below because I have tried all manner of using $and & $elemMatch but can't get it to work.
Thank you
Conversation Model
const conversationSchema = mongoose.Schema(
{
participants: [participantSchema],
},
{timestamps: true}
)
const participantSchema = mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: `User`,
},
username: {
type: String,
required: true,
}
}
)
Conversation Object
{
_id: 61cb6316asas4b54e09168234,
participants: [
{
userId: 61b777ea6815a69a625b,
username: 'johnsmith'
},
{
userId: 61bc0dcbe7181ccfd806,
username: 'testuser'
}
],
createdAt: 2021-12-28T19:18:46.673Z,
updatedAt: 2021-12-28T23:41:12.364Z
}
Queries I have tried that ARE NOT what I need or don't work
// null - no convo found when the convo definitely exists in db
const existingConvo = await Conversation.findOne({
$and: [{ userId: senderId }, { userId: recId }],
})
// works but only checks for ONE id property
// if I make an array: "Query filter must be an object, got an array"
const existingConvo = await Conversation.findOne({
participants: { $elemMatch: { userId: senderId } },
})
// "Unknown operator $and"
const existingConvo = await Conversation.find({
participants: {
$and: [{ userId: senderId }],
},
})
// returns empty array when it should have the convo object
const existingConvo = await Conversation.find({
participants: { $all: [{ userId: senderId }, { userId: recId }] },
})
Say I have this document in my MongoDB collection:
{
_id: 1,
arr: [{
nums: {
a: 2,
},
... (other properties)
},
{
nums: {
a: 3,
},
... (other properties)
}],
... (other properties)
}
How can I delete every object in the arr of this object where the property a in the nums object is equal to 2 using Mongoose. (The _id of the document is given)
I was thinking I could do something like this:
Model.findOneAndUpdate({ _id: 1 }, ???)
But what is '???' ?
EDIT:
This is my configuration (what's in my collection "items"):
{
"_id":{"$oid":"610f8fcc3688bd49e4664c2b"},
"arr":[
{"obj":{"a": 2,"b": 3}}
],
"__v": 0
}
I then run this code:
const mongoose = require("mongoose");
const config = require("config");
const Item = new mongoose.model(
"item",
new mongoose.Schema({
arr: {
type: Array,
required: true,
},
})
);
mongoose
.connect(config.get("mongoURI"), {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
})
.then(async () => {
console.log("Connected to Mongo...");
await Item.findOneAndUpdate(
{ _id: "610f8fcc3688bd49e4664c2b" },
{ $pull: { arr: { "obj.a": 2 } } }
);
})
.catch((err) => console.log(err));
This is my response (what's in my collection after I've executed the code above)
{
"_id":{"$oid":"610f8fcc3688bd49e4664c2b"},
"arr":[
{"obj":{"a": 2,"b": 3}}
],
"__v": 0
}
(nothing has changed)
Btw.: My console doesn't show any errors
I'm trying to update a value inside my array of objects.
Looking at the above mongoDB schema what I want is:
Find an expense with the ID match with the _id and need to update the fields with new ones from the req.body.
Just need to update the: expensesType, description, price and status.
The following code is what I tried to do.
First I need to match the right expense and it works fine but when I try to house.save() show me a message 'house.save is not a function'. So I think maybe I need to use a mongoDB function to get the result.
router.put("/editExpense/:id", ensureAuthenticated, (req, res) => {
var id = mongoose.Types.ObjectId(req.params.id);
House.find(
{ "expensesHouse._id": id },
{
members: 1,
name: 1,
description: 1,
address: 1,
type: 1,
user: 1,
userID: 1,
userType: 1,
expensesHouse: { $elemMatch: { _id: id } },
date: 1
}
).then(house => {
console.log(house);
expenseType = req.body.expenseType;
description = req.body.description;
price = req.body.price;
status = req.body.status;
house.save().then(() => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
});
****** UPDATED ******
After a search I found this updateOne and after adjusts, this is my final result but this way I delete every record..
router.put("/editExpense/:id", ensureAuthenticated, (req, res) => {
var id = mongoose.Types.ObjectId(req.params.id);
House.updateOne(
{ "expensesHouse._id": id },
{
members: 1,
name: 1,
description: 1,
address: 1,
type: 1,
user: 1,
userID: 1,
userType: 1,
expensesHouse: { $elemMatch: { _id: id } },
date: 1
},
{ $set: { "expensesHouse.expenseType": req.body.expenseType } }
).then(house => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
*********** RESOLUTION ***********
I just fixed the problem the way I show below.
House.updateOne(
{ "expensesHouse._id": id },
{
$set: {
expensesHouse: {
expenseType: req.body.expenseType,
description: req.body.description,
price: req.body.price,
status: req.body.status
}
}
}
You are really close to the answer the problem right now that you are having is syntax difference between find and UpdateOne
This is what Find expects, Check MongoDB docs
db.collection.find(query, projection)
This is what updateOne expects, Check Mongo docs
db.collection.updateOne(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)
See the Difference? Second parameter should be update not projection because Update one
returns
matchedCount containing the number of matched documents
modifiedCount containing the number of modified documents
upsertedId containing the _id for the upserted document.
A boolean acknowledged as true if the operation ran with write concern or false if write concern was disabled.
So Your code should be
House.updateOne(
{ "expensesHouse._id": id },
{ $set: { "expensesHouse.expenseType": req.body.expenseType } }
).then(house => {
req.flash("success_msg", "Expenses Updated");
res.redirect("/houses/dashboard");
});
});
House.findOneAndUpdate({userId : req.params.userId},
{ $set: { "expensesHouse.$[element].status": req.body.status } },
{ multi:true, arrayFilters: [{ "element.userID" : req.params.subUserId }], new:true })
Your Api reuquest consist of both the IDs (outer as well as inner) like /api/update/:userId/:subUserId
I am trying to insert data using inertMany .but I am not able to insert the data why ?I am using mongoose session if any error occurred then I roll back changes
https://codesandbox.io/s/dreamy-bell-9u0bz
app.get("/saveData", async (req, res, next) => {
const session = await mongoose.startSession();
session.startTransaction();
try {
const data = [
{
empid: "Ad",
id: 4,
date: "19-Jul-2019"
},
{
empid: "Bc",
id: 56,
date: "18-Jul-2019"
},
{
empid: "C",
id: 6,
date: "11-Jul-2019"
}
];
console.log("before save");
let saveBlog = await BlogPostModel.insertMany(data, { session }); //when fail its goes to catch
await session.commitTransaction();
return res.send(saveBlog);
} catch (error) {
console.log(error);
await session.abortTransaction();
return res.status(400).send(error);
}
});
Since you don't appear to have understood the marked duplicate or the comment on your last question, here's a direct demonstration:
const { Schema } = mongoose = require('mongoose');
const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true, useUnifiedTopology: true };
mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useCreateIndex', true);
mongoose.set('useFindAndModify', false);
const blogPostSchema = new Schema({
id: { type: Number, unique: true },
empid: String,
date: Date
});
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
const sampleData = [
{ empid: "test13", id: 6, date: '11-Jul-2019' },
{ empid: "test123", id: 4, date: '19-Jul-2019' },
{ empid: "test13", id: 4, date: '18-Jul-2019' }
];
const log = data => console.log(JSON.stringify(data, undefined, 2));
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// Clean data
await Promise.all(
Object.values(conn.models).map(m => m.deleteMany())
);
// Collections must existi in transactions
await Promise.all(
Object.values(conn.models).map(m => m.createCollection())
);
// With Transaction
log("With Transaction");
let session = await conn.startSession();
session.startTransaction();
try {
await BlogPost.insertMany(sampleData, { session });
await session.commitTransaction();
} catch(e) {
// Show the error and abort
log({ err: e.errmsg, result: e.result.result.writeErrors });
await session.abortTransaction();
}
log({ results: (await BlogPost.find()) });
// No transaction
log("Without Transaction");
try {
await BlogPost.insertMany(sampleData);
} catch(e) {
// Show the error
log({ err: e.errmsg, result: e.result.result.writeErrors });
}
log({ results: (await BlogPost.find()) });
} catch (e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})();
And the output:
Mongoose: blogposts.createIndex({ id: 1 }, { unique: true, background: true })
Mongoose: blogposts.deleteMany({}, {})
"With Transaction"
Mongoose: blogposts.insertMany([ { _id: 5d8f28ac462a1e1a8c6838a2, empid: 'test13', id: 6, date: 2019-07-10T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a3, empid: 'test123', id: 4, date: 2019-07-18T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a4, empid: 'test13', id: 4, date: 2019-07-17T14:00:00.000Z, __v: 0 } ], { session: ClientSession("650da06d23544ef8bc1d345d93331d1e") })
{
"err": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
"result": [
{
"code": 11000,
"index": 2,
"errmsg": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
"op": {
"_id": "5d8f28ac462a1e1a8c6838a4",
"empid": "test13",
"id": 4,
"date": "2019-07-17T14:00:00.000Z",
"__v": 0
}
}
]
}
Mongoose: blogposts.find({}, { projection: {} })
{
"results": []
}
"Without Transaction"
Mongoose: blogposts.insertMany([ { _id: 5d8f28ac462a1e1a8c6838a5, empid: 'test13', id: 6, date: 2019-07-10T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a6, empid: 'test123', id: 4, date: 2019-07-18T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a7, empid: 'test13', id: 4, date: 2019-07-17T14:00:00.000Z, __v: 0 } ], {})
{
"err": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
"result": [
{
"code": 11000,
"index": 2,
"errmsg": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
"op": {
"_id": "5d8f28ac462a1e1a8c6838a7",
"empid": "test13",
"id": 4,
"date": "2019-07-17T14:00:00.000Z",
"__v": 0
}
}
]
}
Mongoose: blogposts.find({}, { projection: {} })
{
"results": [
{
"_id": "5d8f28ac462a1e1a8c6838a5",
"empid": "test13",
"id": 6,
"date": "2019-07-10T14:00:00.000Z",
"__v": 0
},
{
"_id": "5d8f28ac462a1e1a8c6838a6",
"empid": "test123",
"id": 4,
"date": "2019-07-18T14:00:00.000Z",
"__v": 0
}
]
}
Note that when the transaction is in use there are no items inserted into the collection. Using the insertMany() with the default behavior of ordered: true will insert all batched items up until the point any error is encountered.
Note also as stated since you are indeed expecting an error you must include such a statement in it very own try..catch or similar error handler. Otherwise any error ( which is expected in the example case ) would simply fall to the outer catch, which of course in the demonstration simply exits the program.
Not actually in the question itself but something not actually mentioned in the demonstrations of How to use MongoDB transaction using Mongoose? is indeed that you should be aware that whlist a transaction is active you must also include the session attribute on any subsequent reads in order to see the changes made within that transaction.
For instance, the following would show no content in a collection:
let session = await conn.startSession();
session.startTransaction();
try {
await BlogPost.insertMany(sampleData, { session });
let documents = await BlogPost.find(); // This would return nothing
await session.commitTransaction();
} catch(e) {
// Show the error and abort
log({ err: e.errmsg, result: e.result.result.writeErrors });
await session.abortTransaction();
}
However including the session within a find() will actually show what is inserted:
try {
await BlogPost.insertMany(sampleData, { session });
// Actually includes the session and therefore the state
let documents = await BlogPost.find({},{ session });
await session.commitTransaction();
} catch(e) {
// Show the error and abort
log({ err: e.errmsg, result: e.result.result.writeErrors });
await session.abortTransaction();
}
And of course that read would in this case be dependent on the insertMany() not failing for any reason, since any error would result in exiting to the catch before the next request was made.
Once a transaction is committed, it is of course available to the global state of the connection. But whilst in progress only operations which include the same session information on which the transaction was started will have visibility of any changes implemented within that transaction.
For who get the error "Cannot read property 'map' of undefined" while passing session as option in inserMany, this errors come because your mongo is running as standalone servers, to fix this can refer npm package run-rs or following this answer to fix this: https://stackoverflow.com/a/60603587/9611273