How to get MongoDB _id of an inserted document - node.js

I want to create a document in my MongoDB database and take the _id of the new document.
This is what I'm doing:
const mongoose = require("mongoose");
const billingSchema = require("./models/billing");
const { ObjectId } = require("bson");
const { MongoClient } = require("mongodb");
const mongouri = "***";
var connection = mongoose.createConnection(mongouri);
var Bills = connection.model("Fatturazione", billingSchema, "Fatturazione");
exports.createBill = (b) => {
return new Promise((resolve, reject) => {
Bills.Create(b, function (err) {
if (err) {
reject(err);
} else {
console.log(mongoose.Types.ObjectId(b._id));
resolve();
}
});
});
};
and this is my Schema:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//schema define the structure of the document
const billingSchema = new Schema({
data_fatturazione: {
type: Date,
required: true,
},
data_saldo: {
type: Date,
required: false,
},
totale: {
type: Number,
required: false,
},
pagato: {
type: Boolean,
required: false,
},
});
module.exports = billingSchema;
In the console.log() I want to print the _id of the last inserted document but it prints a non-existing id (it doesn't correspond to the _id of the last created document in the database). I also tried without using mongoose.Types.ObjectId() but it prints undefined. I don't understand where is the problem.
I call the function createBill() in another js file, passing an object with the correct fields.

You are trying to get the _id of argument b, which is passed to your createBill, which is logically undefined. Instead you must get the _id from a result of Bill.create, mongoose callbacks take 2 arguments as #Joe mentioned in the comments, so your code must look like this:
exports.createBill = (b) => {
return new Promise((resolve, reject) => {
Bills.Create(b, function (err, result) {
if (err) {
reject(err);
} else {
console.log(result._id);
resolve(result);
}
});
});
};

Related

Mongoose user.save() doesn't return updated _id

I have a simple code that uses mongoose with nodejs to save a user object but when I log the result object that is return from save() method it is just the object I sent and the _id and id values are undefined.
Still, the object is saved correctly in the database with the new _id.
this is my code
`
import { mongoose } from "mongoose";
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
required: true,
},
age: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
});
export const addUser = async (_user) => {
let user = new User({ ..._user });
let result;
try {
result = await user.save();
console.log(result._id);
} catch (err) {
console.log(err);
}
return result;
};
`
I expect console.log(result._id) to have the new generated Id but it is undefined even though it is saved correctly to the database
The solution that worked for me is to assign the _id before calling save()
export const addUser = async (_user) => {
let user = new User({ ..._user });
user._id = mongoose.Types.ObjectId();
let result;
try {
result = await user.save();
console.log(result._id);
} catch (err) {
console.log(err);
}
return result;
};

Mongoose - Cannot modify field value

I am building a simple shop backend for practice purposes. I have three schemas Product, Customer and Order.
What I am trying to achieve is to subtract the ordered quantity from the stock quantity for each product inside an order, when the order is created. Clearly I am doing something wrong cause my productsToUpdateInDbArray contains the correct products (checked it with console log) but I can't find a way to make it work.
stockQty field inside Products collection is not updating.
My controller code is:
'use strict'
// require validator for string validation
const validator = require('validator');
// import Order, Customer, Product Models
const Order = require("../models/order.model");
const Customer = require("../models/customer.model");
const Product = require("../models/product.model");
// DEFINE CONTROLLER FUNCTIONS
// listAllOrders function - To list all orders
exports.listAllOrders = (req, res) => {
Order.find({}, (err, orders) => {
if (err) {
return res.status(500).send(`Internal server error: ${error}`);
}
if (orders && orders.length === 0) {
return res.status(404).send(`No orders found!`);
}
return res.status(200).json(orders);
});
};
// createNewOrder function - To create new order
exports.createNewOrder = (req, res) => {
const customerId = req.body?.customerId;
const productsArray = req.body?.products;
let productsToUpdateInDbArray = [];
if (!validator.isMongoId(customerId)) {
return res.status(400).send('Invalid customer Id');
}
Customer.findById(customerId, async (err, customer) => {
if (err) {
return res.status(500).send(`Internal server error: ${error}`);
}
if (!customer) {
return res.status(404).send(`No customers found!`);
}
if (!productsArray || productsArray.length === 0) {
return res.status(400).send(`No products found in the order!`);
}
for (let product of productsArray) {
if (!validator.isMongoId(product?.productId)) {
return res.status(400).send('Invalid product Id');
}
if (!product?.quantity || product?.quantity < 1) {
return res.status(400).send('Invalid product quantity');
}
let productFound = await Product.findById(product?.productId).exec();
if (!productFound) {
return res.status(404).send('Product not found!');
}
if (productFound.stockQty < product.quantity) {
return res.status(400).send('Not enough product quantity in stock')
}
productFound.stockQty -= product.quantity;
productsToUpdateInDbArray.push(productFound);
}
console.log(productsToUpdateInDbArray)
const newOrder = new Order(req.body);
newOrder.save((err, order) => {
if (err) {
return res.status(500).send(`Internal server error: ${error}`);
}
for (let item of productsToUpdateInDbArray) {
const filter = { _id: item._id };
const update = { stockQty: item.stockQty };
Product.findOneAndUpdate( filter, update )
}
return res.status(201).json(order);
});
});
};
And my models are:
'use strict';
// Import mongoose
const mongoose = require("mongoose");
// Declare schema and assign Schema class
const Schema = mongoose.Schema;
// Create Schema Instance and add schema propertise
const ProductSchema = new Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
description: {
type: String,
required: true
},
imageUrl: {
type: String,
required: true
},
stockQty: {
type: Number,
required: true
}
});
// create and export model
module.exports = mongoose.model("Products", ProductSchema);
'use strict';
// Import mongoose
const mongoose = require("mongoose");
// Declare schema and assign Schema class
const Schema = mongoose.Schema;
// Create Schema Instance and add schema propertise
const OrderSchema = new Schema({
products: [
{
productId: {
type: Schema.Types.ObjectId,
required: true,
ref: "Products"
},
quantity: {
type: Number,
default: 1
}
}
],
customerId: {
type: Schema.Types.ObjectId,
required: true,
ref: "Customers"
}
});
// create and export model
module.exports = mongoose.model("Orders", OrderSchema);
findOneAndUpdate will only execute the query when a callback is passed. So in your case you can either add an await or callback.
await Product.findOneAndUpdate( filter, update );
or
Product.findOneAndUpdate( filter, update, callback );

Getting an empty array Mongoose

I can not get data from my MongoDb collection via mongoose - I'm getting an empty array out of my request. It only happens when I'm using a route which I posted below.
Code
router.get("/options", async (req,res) => {
try {
const { animalClass} = req.body;
if (!animalClass) {
const animalClasses = await AnimalClass.find({});
console.log(animalClasses);
return res
.status(200)
.json({animalClasses})
} else {
const animalTypes = await AnimalType.find({class: animalClass});
console.log(animalTypes);
return res
.status(200)
.json({animalTypes})
}
} catch (err) {
res
.status(500)
.json({msg: err})
}
});
Schema
const mongoose = require('mongoose');
const animalClassSchema = new mongoose.Schema({
name: {type: String, required: true}
})
module.exports = AnimalClass = mongoose.model('animalClass',animalClassSchema);
Specify the collection name when creating the schema, like:
const animalClassSchema = new mongoose.Schema({
name: {type: String, required: true}
}, { collection: 'animalClass' });
By default, Mongoose pluralizes your collection name. This option allows you to override that behavior. More info in the docs:
https://mongoosejs.com/docs/guide.html#collection

Cascade Delete in mongo

I am new to MongoDB. I created 4 collections & they are connected with each other. (I am using node.js to write it)
Here, it's my question. How can I delete all records at once? Is there something like deep level population?
This one holds all models.
const DataModel = mongoose.Schema({
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', require: true},
order: { type: mongoose.Schema.Types.ObjectId, ref: 'Order', require: true},
});
User model
const userSchema = mongoose.Schema({//other stuff});
Order model
const orderSchema = mongoose.Schema({
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
//other stuff
});
Product model
const productSchema = mongoose.Schema({//other stuff});
I can delete the entry with these code from the database, but the other entries still there
exports.delete_data = (req, res, next) => {
const id = req.params.userId;
userDataModel.deleteOne({_id: id})
.exec()
.then(docs => {
res.status(200).json({
message: 'Record Deleted',
request: {
type: 'POST'
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
Update: However, I wonder, Could I call other defined delete functions for order, product inside delete_data
As #Geert-Jan suggest, cascade delete is my solution. The link that geert-jan gave solve my problem. However, I wonder, Could I call other defined delete functions for order, product inside delete_data
i did this and it could be good for someone who wants to delete documents in cascade linked to any field of a model.
async blackHole() {
try {
const rtn = new ApiResponse<any>();
const userId = id;
const accountId = mongoose.Types.ObjectId(id);
var CollectionNames: any[] = [];
mongoose.connection.db.listCollections().toArray(function (err, collections) {
CollectionNames = collections.map(c => c.name);
CollectionNames.forEach((element: any) => {
mongoose.connection.db.collection(element).deleteMany({ "account": accountId });
});
});
const accountController = new AccountController(this.wsParams);
await accountController.delete(id)
await super.delete(userId);
return rtn;
} catch (error: any) {
const rtn = new ApiResponse<any>();
rtn.message = error;
rtn.success = false;
rtn.status = 422;
return rtn;
}
}
I hope you can use it :D

Execute a model operation inside a different model hook using mongoose

I want to trigger a remove operation to a ModelB inside a mongoose pre.save hook from a ModelA.
Basically any time any ModelA is updated, I need to drop the ModelB collection:
This is what I tried, I don't get errors but the operations never ends:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
const permissionSetSchema = require('./permission-set');
const PermissionSet = mongoose.model('PermissionSet', permissionSetSchema);
const roleSchema = new Schema({
name : { type: String, required: true, unique: true, maxLength: 140 },
description: { type: String, maxLength: 300 },
});
roleSchema.post('update', (next, done) => {
PermissionSet.remove({}, err => {
if (err) { next(err); }
next();
});
});
The first arg is the document. The second is the next callback.
Should be:
roleSchema.post('update', (doc, next) => {
PermissionSet.remove({}, err => {
if (err) { next(err); }
next();
});
});
http://mongoosejs.com/docs/middleware.html

Resources