Process multiple update nodejs mongodb - node.js

I have a function to update some values from a subdocument, but I am having troubles updating the data
let query = InvoiceModel.find({
is_draft:false
products.product: productid
})
query.exec(function (err, data) {
if (data) {
data.forEach(function(si) {
let saleinvoice_id = si._id
console.log(saleinvoice_id);
InvoiceMovement(invoice_id, si)
})
}
})
In the InvoiceMovement function I search for the record in the collection PRODUCT to update and try to update the array like this:
productModel.findOneAndUpdate({
_id: product_id,
'warehouses.warehouse': warehouse_id
}, {
$set: {
"warehouses.$.stock": stock_data,
}
}, function (errwu, wupdated) {
if (errwu) {
console.log(errwu);
}
if (wupdated) {
console.log(wupdated);
}
})
But not all the data is processed.
For an specific ID I have 4 invoices records, but only two or less affect the value to update in the product collection
I try using async.forEach , but I get the same result.
UPDATE
Schemas:
INVOICE
const InvoiceSchema = Schema({
invoice_number: {
type: String,
},
products: [{
product: {
type: Schema.Types.ObjectId,
ref: 'products',
required: [true, 'Producto no puede estar vacio']
},
warehouse: {
type: Schema.Types.ObjectId,
ref: 'warehouses'
},
work_order: {
type: Schema.Types.ObjectId,
ref: 'work_orders'
},
quantity: {
type: Number,
required: [true, 'Cantidad no puede estar vacio']
},
base_price: {
type: String,
required: [true, 'Valor Unitario no puede estar vacio']
},
sale_price: {
type: String,
required: [true, 'Valor Unitario no puede estar vacio']
},
discount: {
type: String,
default: "0.00"
},
subtotal: {
type: String,
required: true
},
tax: {
type: String,
required: true
},
total: {
type: String,
required: true
},
}]
}, {
timestamps: true
});
PRODUCT
const productSchema = Schema({
code: {
type: String,
index: true
},
name: {
type: String,
index: true,
required: [true, 'Nombre no puede estar vacio']
},
description: {
type: String,
required: [true, 'Descripcion no puede estar vacio']
},
unit: {
type: String,
index: true,
required: [true, 'Unidad no puede estar vacio']
},
exempt: {
type: Boolean,
default: false
},
product_category: {
type: Schema.Types.ObjectId,
ref: 'product_categories',
required: [true, 'Categoría de Producto es requerida']
},
base_price: {
type: String,
default: "0.00"
},
unit_cost: {
type: String,
default: "0.00"
},
warehouses: [
{
warehouse: {
type: Schema.Types.ObjectId,
ref: 'warehouses',
required: [true, "Seleccione una caracteristica"]
},
stock: {
type: Number,
},
unit:{
type: String
}
}
],
subproducts: [
{
subproduct: {
type: Schema.Types.ObjectId,
ref: 'characteristics',
// required: [true, "Seleccione una caracteristica"]
},
}
],
stock: {
type: Number,
default: 0
}
}, {timestamps: true});
From the Invoice Schema I go through the products array, to get the product ID and the quantity, with that data I update the stock in the warehouses array inside the PRODUCT schema.
I Need to do this for every Invoice.
One invoice can have many product registered

Below is one way you can do this. However, this might be easier if you use mongoose.promise.
InvoiceModel.find({}, 'products', function(err, invoice) {
if(err) throw err
const products = invoice.products
// Loop through all the objects in the array
products.forEach(function(productsObj) {
// Get the product model for each product
ProductModel.findById(productsObj.product, 'warehouses', function(err, product) {
if(err) throw err
// Get a new array of only ids
const warehousesIds = product.warehouses.map(warehousesObj => {
return warehousesObj.warehouse
})
// Get the index of the current warehouse in the warehouses array in your product model
const warehouseIndex = warehousesIds.indexOf(productsObj.warehouse)
// Check if warehouse exists and if so assign the new value
if(warehouseIndex > -1) product.warehouses[warehouseIndex].stock = productsObj.quantity
// Save your model
product.save()
})
})
})
Hope it helps!

Related

How to get data from mongoDB on the basis of a value inside a nested object

Below is my API for fetching all the orders of a specific restaurant from a mongoDB database.
My search is based on the restaurant id which I am getting from params and passing it to the query object.
query1 is working but query2 does not return my data.
It is returning an empty array. If I pass a simple object in find() then I am getting a response. But when i use a nested object for getting data I get nothing.
exports.getOrders = async (req, res) => {
const restId = req.params.restId;
console.log("restaurant id", restId);
if (!restId) return res.status(404).send("No restaurant ID found in params");
const query1 = {grandTotal: 600};
const query2 = { restaurant: { restaurantId: restId } };
const response = await Orders.find(query2);
console.log("Printing response inside API function", response);
}
Below is my MongoDB Schema of Orders.
const mongoose = require("mongoose");
const orderSchema = mongoose.Schema({
customer: {
name: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
customerId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer",
required: true,
},
customerAddress: {
type: String,
required: true,
},
},
restaurant: {
restaurantName: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
restaurantId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
required: true,
},
},
/*date: {
day: {
type: Number,
required: true,
},
month: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
},
type: {
type: String,
enum: ["delivery","takeaway"],
required: true,
},*/
items: [
{
itemId: { type: String, required: true },
itemName: { type: String, required: true },
itemDescription: { type: String, required: true },
price: {type: Number, required: true},
quantity: { type: Number, required: true },
total: {type: Number, required: true},
},
],
grandTotal: {type: Number, required: true},
status: {
type: String,
enum: ["pending", "rejected","cancelled","accepted","received"],
required: true,
},
});
orderSchema.virtual("booking", {
ref: "Booking",
localField: "_id",
foreignField: "orderId",
});
orderSchema.set("toObject", { virtual: true });
orderSchema.set("toJSON", { virtual: true });
const Orders = mongoose.model("Orders", orderSchema);
exports.Orders = Orders;
change query2 to this
const query2 = { "restaurant.restaurantId": restId } };

want to show orders only to specific product owners to which orders has been given in mongodb MERN STACK DEVELOPMENT

This is my order Schema
the person who actually starts the order , can get his SPECIFIC ORDERS, but the person who gets order to his product can not get specific orders.Which are his , i am copying a tutorial and making a product please help with that
const mongoose = require('mongoose')
const orderSchema = mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true
},
city: {
type: String,
required: true
},
phoneNo: {
type: String,
required: true
},
postalCode: {
type: String,
required: true
},
country: {
type: String,
required: true
}
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product'
}
}
],
paymentInfo: {
id: {
type: String
},
status: {
type: String
}
},
paidAt: {
type: Date
},
itemsPrice: {
type: Number,
required: true,
default: 0.0
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
orderStatus: {
type: String,
required: true,
default: 'Processing'
},
deliveredAt: {
type: Date
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema)
this is my product schema
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter product name'],
trim: true,
maxLength: [100, 'Product name cannot exceed 100 characters']
},
price: {
type: Number,
required: [true, 'Please enter product price'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0.0
},
description: {
type: String,
required: [true, 'Please enter product description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
}
],
category: {
type: String,
required: [true, 'Please select category for this product'],
enum: {
values: [
'Electronics',
'Cameras',
'Laptops',
'Accessories',
'Headphones',
'Food',
"Books",
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
message: 'Please select correct category for product'
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter product stock'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product', productSchema);
these are my order controller function
exports.myOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
res.status(200).json({
success: true,
orders
})
})
// Get all orders - ADMIN => /api/v1/admin/orders/
exports.allOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
//let totalAmount = 0;
/* orders.forEach(order => {
totalAmount += order.totalPrice
})
*/
res.status(200).json({
success: true,
// totalAmount,
orders
})
})
the user who initiate the order can see the orders which he initiated but the person to which order was given can not get specific order
I hope i make it clear enough , please help me I am a noob
For user you can use Model.find({ user: user_id });
For seller, you should use Model.find({ user: user_id, seller: seller_id })
This will match orders from the USER for the SELLER

How to delete the referenced document in one collection and its record from the referred other collection

In my NodeJS API and MongoDB, I'm trying to delete a record which is a reference to another collection.
What I would like to do is to delete the referred objectId and the records related to the other collection which is referred.
I have 2 models Profiles and Posts and I want to delete the same one post from Profile and Post collection.
I was able to delete the reference id in Profile but I don't know how to delete also the record from Posts collection.
I tried this:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
err => {
if (err) {
throw new ErrorHandlers.ErrorHandler(500, err);
}
res.json({ Message: "Deleted" });
}
);
} catch (error) {
res.status(500).send(error);
}
}
And my 2 models:
// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");
const postSchema = {
type: Connect.Schema.Types.ObjectId,
ref: "Post"
};
const experienceSchema = {
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date,
required: false
},
description: {
type: String,
required: false
},
area: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
username: {
type: String,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
};
const profileSchema = {
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: [true, "Email is required"],
validate: {
validator: string => isEmail(string),
message: "Provided email is invalid"
}
},
bio: {
type: String,
required: true
},
title: {
type: String,
required: true
},
area: {
type: String,
required: true
},
imageUrl: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
},
username: {
type: String,
required: true,
unique: true
},
experience: [experienceSchema],
posts: [postSchema],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
};
const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);
module.exports = Profile;
const { Connect } = require("../db");
const reactionSchema = {
likedBy: {
type: String,
unique: true,
sparse: true
}
};
const postSchema = {
text: {
type: String,
required: true,
unique: true,
sparse: false
},
profile: {
type: Connect.Schema.Types.ObjectId,
ref: "Profile",
},
image: {
type: String,
default: "https://via.placeholder.com/150",
required: false
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
reactions: [reactionSchema],
comments: {
type: Connect.Schema.Types.ObjectId,
ref: "Comment",
required: false
}
};
const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);
module.exports = Post;
Just add a query to remove the post after pulling it's ID from the profile collection:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
// You don't need an error callback here since you are
// using async/await. Handle the error in the catch block.
);
await Posts.remove({ _id: req.params.postId });
} catch (error) {
// This is where you handle the error
res.status(500).send(error);
}
}

MongoD: How to update specific field of a document in a collection?

I have a collection of jobs in MongoDB and in this collection there is a field in the documents named as appliedUser. I want to update this field when a new user applies for this job.So basically this field stores the id's of all the users who are applying for this job.
I am using findOneAndUpdate() function but not able to do it.
Job.findOneAndUpdate({ _id: req.params.id }, { $set: { appliedUser:
req.user.id } }, function(err, job) {
console.log(job);
})
and here is my Schema:
const jobSchema = new Schema({
date: { type: Date, default: Date() },
expirydate: { type: Date, required: true },
name: { type: String, required: true },
companydetails: { type: String, required: true },
address: { type: String, required: true },
role: { type: String, required: true },
city: { type: String, required: true },
minsalary: { type: Number, required: true },
maxsalary: { type: Number, required: true },
skills: { type: Array, required: true },
minex: { type: Number, required: true },
appliedUser: [{ type: Schema.Types.ObjectId, ref: 'users', unique:
true }],
user: { type: String, required: true }
})
The array of the document is not updating. I am not able to find the errors.
Look like what you need is $addToSet. Example:
Job.findOneAndUpdate({ _id: req.params.id }, { $addToSet: { appliedUser: req.user.id } }, function(err, job) {
console.log(job);
})

Mongodb, search for text and geolocation in different collections

I have 3 collections: business, sevice, employee.
I need search by service (without fulltext), by employee and by the geolocation of each business, and should show only business.
var BusinessSchema = new Schema({
business_id: {
type: String,
required: true,
unique:true
},
name: {
type: String,
required: true
},
email: {
type: String,
},
description:{
type: String
},
location:{
country:{
type:String,
},
city:{
type:String
},
coord:[Number]
}
services:[{
type: Schema.Types.ObjectId,
ref: 'Service'
}]
},
{
timestamps: true
});
var ServiceSchema = new Schema({
business:{
type: Schema.Types.ObjectId,
ref: 'Business'
},
category:{
type: Schema.Types.ObjectId,
ref: 'Category',
index:true
},
name: {
type: String,
required: true,
index:true
},
employee: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
{
timestamps: true
});
var UserSchema = new Schema({
birthday:Date,
first_name: {
type: String,
required: true
},
last_name: {
type: String,
required: true
},
email: {
type: String,
unique: true,
match: [/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'Please fill a valid email address'],
required: true
},
password:{
type: String
},
{
timestamps: true
});
What changes should i make collections to optimize the query?
Service.distinct('business',filter_services)
.exec(function (err, business) {
if (err) {
return cb({ status: 400, message: err }, null);
} else {
if(business.length > 0){
var filter_business = [{is_active:true},{is_approved:true}]
filter_business.push({_id:{$in:business}})
filter_business.push({location.coord:input_coord}})
filter_business = {$and:filter_business}
Business.find(filter_business)
.select('name services')
.exec(function (err,result){
if(err){
return cb({ status: 400, message: err }, null);
}
else{
if(result.length > 0){
var total = result.length;
}
return cb(null, result);
}
})
}
// si no hay business en el primer query, se retorna [].
else{
return cb(null, business);
}
}
});
Could geo filter by text and at the same time to get closer to a point?
For now, i am not using the Employee collection, but, if i would search by business name, employee name and service name simultaneously, what changes should make.
Your business model should be
var BusinessSchema = new Schema({
business_id: {
type: String,
required: true,
unique:true
},
name: {
type: String,
required: true
},
email: {
type: String,
},
description:{
type: String
},
address:{
country:{
type:String,
},
city:{
type:String
}
},
location : {
type: [Number],
index: '2dsphere'
},
services:[{
type: Schema.Types.ObjectId,
ref: 'Service'
}],
employees:[{
type: Schema.Types.ObjectId,
ref: 'User'
}]
},
{
timestamps: true
});
The change in schema is you have to create index on location, and for find business based on employee have to add employees id in business schema.Then you can you geo near query of mongodb.

Resources