how to unset (delete) field in findByIdAndUpdate in mongoDB - node.js

I have an API that update a post and I want when a field is passed as undefined to delete this field or at least set it to undefined.
Here is my current implementation but it's not working:
const finalData = {
_id,
...,
mileage,
};
const result = await provider.updatePost(finalData);
and my provider
updatePost: async (payload) => {
const { _id, ...newData } = payload;
const result = await Model.findByIdAndUpdate(_id, newData, {
new: true,
omitUndefined: true,
});
await indexPost(result);
if (!result) {
throw new NotFound('No post found');
}
return result;
}

Related

Nodejs exports returns undefined on mongoose Insertion

I have created nodejs application by organising as module structure , The problem I am facing is that a mongodb insertion return undefined value from one of my controller, The issue I found is that my async funtion doesn't wait to complete my mongodb operation But I could not find a solution for that, my route and controller code is given below
route.js
const {
createEvent, editEvent
} = require('./controller');
router.post("/event/create", validateEventManage, isRequestValidated, async(req, res) => {
let data = {};
data.body = req.body;
try{
let event = await createEvent(req.body);
console.log(event) // returned undefined
data.event = event;
res.status(200).json(data);
}catch(error){
console.log(error)
res.status(200).json({error:error});
}
});
controller.js
exports.createEvent = async(data) => {
// return "test" // This works correctly
const eventObj = {
name : data.name,
description : data.desc,
type : data.type,
startDate : new Date()
}
const event = await new Event(eventObj);
await event.save((error,event)=>{
if(error) {
return error;
}
if(event){
return event;
}
});
}
You should not await the new Event constructor.
Also, since you are using async - await you can
remove the callback from the save and try ... catch the error to handle it:
exports.createEvent = async (data) => {
// return "test" // This works correctly
const eventObj = {
name: data.name,
description: data.desc,
type: data.type,
startDate: new Date(),
};
try {
const event = new Event(eventObj);
await event.save();
return event;
} catch (error) {
return error;
}
};

ClientSession cannot be serialized to BSON - Mongodb Transaction

I'm fairly new to mongodb transaction so I have no idea what I did wrong. I've followed the direction in the documentation but I still get this error
{
"status": 400,
"name": "Error",
"message": "ClientSession cannot be serialized to BSON."
}
Here's my code
async createInsurance(params) {
const session = await db99.startSession();
try {
session.startTransaction();
const doc = await db.insurance
.find({ session })
.sort({ createdAt: -1 })
.limit(1)
.lean();
const latest = doc[0];
const payload = { ...params, id: latest ? latest.id + 1 : 1 };
const data = await db.insurance.create(payload, { session });
await mongoTransaction.commitWithRetry(session);
const result = defaultResult('SuccessCreateInsurance', SuccessCreateInsurance[this.lang], data, 200);
return result;
} catch (error) {
logger.log('error', 'ProductService-createInsurance', { error });
throw error;
} finally {
await session.endSession();
}
}
Is there anything I missed?
The documentation for Model.create indicates that the documents must be passed in an array in order to specify options:
[options] «Object» Options passed down to save(). To specify options, docs must be an array, not a spread.
Change
const payload = { ...params, id: latest ? latest.id + 1 : 1 };
to
const payload = [{ ...params, id: latest ? latest.id + 1 : 1 }];
turns out I have to pass session on the 3rd parameter on find method and wrap payload as an array on create method cause it can only take an array.
the code will look like this
async createInsurance(params) {
const session = await db99.startSession();
session.startTransaction();
try {
const doc = await db.insurance
.findOne(null, null, { session })
.sort({ createdAt: -1 })
.limit(1)
.lean();
const latest = doc[0];
const payload = { ...params, id: latest ? latest.id + 1 : 1 };
const data = await db.insurance.create([payload], { session });
await session.commitTransaction();
const result = defaultResult('SuccessCreateInsurance', SuccessCreateInsurance[this.lang], data, 200);
return result;
} catch (error) {
await session.abortTransaction();
logger.log('error', 'ProductService-createInsurance', { error });
throw error;
} finally {
await session.endSession();
}
}

I get undefined value when I make a request to the MongoDB database using the mongodb engine in Nodejs

I am using ExpressJS and MongoDB to create a blog for myself. I have created a mini library with the mongodb module to request the MongoDB database.
Here is the library:
'use strict'
const { MongoClient, ObjectId } = require('mongodb')
const { config } = require('../config')
const USER = encodeURIComponent(config.mongodb.user)
const PASS = encodeURIComponent(config.mongodb.pass)
const NAME = config.mongodb.name
const HOST = config.mongodb.host
const URL = `mongodb+srv://${USER}:${PASS}#${HOST}/${NAME}?retryWrites=true&w=majority`
const OPTIONS = {
useNewUrlParser: true,
useUnifiedTopology: true
}
class MongoLib {
constructor () {
this.client = new MongoClient(URL, OPTIONS)
this.name = NAME
}
connect () {
if (!MongoLib.connection) {
MongoLib.connection = new Promise((resolve, reject) => {
this.client.connect(err => {
if (err) reject(err)
console.log('Connected successfully to MongoDB.')
resolve(this.client.db(this.name))
})
})
}
return MongoLib.connection
}
getAll (collection, query) {
return this.connect().then(db => {
return db.collection(collection).find({ query }).toArray()
})
}
get (collection, id) {
return this.connect().then(db => {
return db.collection(collection).findOne({ _id: ObjectId(id) })
})
}
create (collection, data) {
return this.connect().then(db => {
return db.collection(collection).insertOne(data)
}).then(result => result.insertedId)
}
update (collection, id, data) {
return this.connect().then(db => {
return db.collection(collection).updateOne({ _id: ObjectId(id) }, { $set: data }, { upsert: true })
}).then(result => result.upsertedId || id)
}
delete (collection, id) {
return this.connect().then(db => {
return db.collection(collection).deleteOne({ _id: ObjectId(id) })
}).then(() => id)
}
}
module.exports = MongoLib
The database is connecting correctly because I have a seed that injects data into the database using the create method of the library that you just saw.
In the service layer, I create a class with a method called getUser, which will call the getAll method of the MongoDB library, to which we pass a query so that it looks for the user.
'use strict'
const MongoLib = require('../lib/mongo')
const bcrypt = require('bcrypt')
class UsersService {
constructor () {
this.collection = 'users'
this.mongoDB = new MongoLib()
}
async getUser ({ email }) {
// { email } is getted by basic authentication as a "username" to login
// I am receiving this data perfectly
const [user] = await this.mongoDB.getAll(this.collection, { email })
// But the problem start here, the value of user is undefined
return user
}
async createUser ({ user }) {
const { name, email, password } = user
const hashedPassword = await bcrypt.hash(password, 10)
const createUserId = await this.mongoDB.create(this.collection, {
name,
email,
password: hashedPassword
})
return createUserId
}
}
module.exports = UsersService
The problem here is that the user value is undefined. I don't understand why it causes conflict. I'm using async-await to wait for the database request to finish, and the data is in the database correctly.
Does anyone have an idea about this error? If more information needs it, please let me know.
Suspect your query is wrong, you are sending { { email: email } } to mongodb
getAll (collection, query) {
return this.connect().then(db => {
return db.collection(collection).find(query).toArray()
})
}

I want to delete all the item but except of the current user

I am creating a call that deletes all the users except the current user logged in.
Here is my code;
exports.deletealluser = async (req, res) => {
try {
const { sub } = req.user;
const usersExceptCurrent = await User.find({ _id: !sub });
const deletedUsers = await User.deleteMany(usersExceptCurrent);
res.status(201).json({
message: 'A all user is successfully deleted!',
deletedUsers,
});
} catch (err) {
return res.status(400).json({
message: 'Something went wrong.',
});
}
};
sub is the id of the current user. As you can see, I call find query first to filter the data which is not equal to sub. Then I use the usersExceptCurrent as filter to my deleteMany query.
But it returns status 400
And here is my axios call;
const onDelete = async () => {
try {
const { data } = await fetchContext.authAxios.delete(
'admin/delete-all-users'
);
fetchContext.setUserList(
fetchContext.userList.filter((row) => row === data.deletedUsers)
);
setSignupSuccess(data.message);
setSignupError('');
setOpen(false);
setOpenAlert(false);
} catch (err) {
setIsLoaded(true);
setError(err);
const { data } = err.response;
setSignupError(data.message);
setSignupSuccess('');
}
};
Use $ne
$ne selects the documents where the value of the field is not equal to the specified value. This includes documents that do not contain the field.
db.collection.find({ _id: { $ne: sub } })
Demo - https://mongoplayground.net/p/ecMNn4ueZrn
If you still face for _id should be ObjectId you can do
const ObjectId = require("mongodb").ObjectId;
db.collection.find({ _id: { $ne: ObjectId(sub) } })
See what ! does, converts to bool value in JS
console.log(!"a");
console.log(!2);

Updating a nested objects in Mongoose

I have the following express route:
const updateSnapshot = async (req, res) => {
const accountId = req.body.account_id;
if (!accountId) {
return fail(res, 'account id is missing', 400);
}
try {
const account = await Account
.findOne({ _id: accountId})
.populate({
path: 'snapshot',
model: 'Snapshot'
});
// I want to update these fields in snapshot
const snapshot = {
friends_count: data.friends_count,
updated_date: new Date()
};
account.snapshot.friends_count = snapshot.friends_count;
account.snapshot.updated_date = snapshot.updated_date;
await account.save();
return success(res, snapshot);
} catch(error) {
fail(res, error.message, 500);
}
};
I want to update the nested object snapshot (just the fields friends_count and update_date) however when I check the database it seems to have not work. What am I doing wrong here?
const updateSnapshot = (req, res) => {
const accountId = req.body.account_id;
if (!accountId) {
return fail(res, 'account id is missing', 400);
};
Account
.findOneAndUpdate({ _id: accountId }, {
$set: {
snapshot: {
friends_count: data.friends_count,
updated_date: new Date()
}
}
}, {
new: true
})
.then(account => {
if(!account) {
return fail(res, "Account not found", 404);
} else {
return success(res, account);
};
})
.catch(err => {
return fail(res, error.message, 500);
});
};
Here we're using the findOneAndUpdate method and promises to find and update the document in one operation.
findOneAndUpdate takes the query criteria as the first parameter, the second parameter updates values specified in the object (we're using the $set operator to update specific values of the snapshot object), and the three parameter is an object that defines the operation's options (new is set to true to return the newly updated object).
Note: $set will replace the entire snapshot object so if there are other properties inside the snapshot object, they will need to be included inside the $set object.

Resources