Inserting products to subschema taking long time? - node.js

I have mongoose schema:
var productSchema = new Schema({
"productId" : {type : String},
"productName" : {type : String},
"mrp" : {type : String}
});
var shopSchema = new Schema({
"ShopId" : {type : Number},
"Name" : {type : String},
"contact" : {type : Number},
"products" : [productSchema]
},{collection:"shopProductDetails"});
module.exports.Shops = mongoose.model('Shops',shopSchema);
module.exports.Products = mongoose.model('Products',productSchema);
I inserted data into the shop successfully .Next I have to insert data into the sub schema that is productSchema
Insertion Data
{
"ShopId":"439",
"products": [{
"productId": "1234",
"productName": "non veg",
"mrp": "38",
}, {
"productId": "5678",
"productName": "veg",
"mrp": "38 "
},{...}]
}
Products Insertion Code:
model.Shops.findOne({"ShopId":439},function(err, doc){
if(doc == null){
res.json({'success':'0','result':{},'errorMessage':'Credentials not matched'});
}
else{
async.each(products,function(item){
var insertProducts={productId: item.productId, productName: item.productName, mrp: item.mrp};
doc.products.push(insertProducts)
});
doc.save(function (err, data) {
if (err) {
res.json({'errorMessage':err});
}
else {
res.json({'success':'1','result':{'message':'Products Inserted Successfully'},'errorMessage':'No'});
}
});
}
});
Here the products are inserted successfully, the problem is that it is taking a large time when there is a bulk data. I am using async here,i think its wrong.Can any one suggest a better approach

I would suggest you only having the reference id for the product in the shop. It will save you time when making the query (now you just have to insert an id instead of looking up for another document in the database).

Related

How to specify and update an object within array in MongoDB

I'm trying to update the values of an object placed inside the array.
The MongoDB schema is as follows:
const ServiceStatus = new Schema({
CustomerName : { type : String},
CustomerNumber : {type : String},
ServiceName : {type : String},
Details : {type: String},
Date : {type: String},
Status : {type : String},
Comments : {type : String},
ServiceId : {type: Schema.Types.ObjectId},
CustomerId : {type: Schema.Types.ObjectId},
ServiceProvider : {type: Schema.Types.ObjectId},
message : [{
sender : {type: String},
content : {type : String},
time : {type : String}
}]
})
and the snippet of the route is
router.put('/message/customer/:id',(req, res) => {
const id=req.params.id;
Status.findByIdAndUpdate({_id : id},
{
$push : {
"message.$.sender": "Customer" ,
"message.$.content": req.body,
"message.$.date" : new Date()
}
}
,{ useFindAndModify: false } )
.exec((err, status) => res.json(status))
})
When I tried running it on postman it doesn't get updated but I don't get any error. I want to know how I should change the router to make it work.
I think it should be like this one:
db.ServiceStatus.insertOne(
{
CustomerName: "the name",
message: [{ sender: "Customer", content: "some content", time: new Date() }]
}
);
db.ServiceStatus.updateOne(
{ CustomerName: "the name" },
{
$push: {
message: { sender: "Another customer", content: "more content", time: new Date() }
}
}
)
db.ServiceStatus.find()
{
"_id" : ObjectId("5fdc4f14d1d3de1f92780a0b"),
"CustomerName" : "the name",
"message" : [
{
"sender" : "Customer",
"content" : "some content",
"time" : ISODate("2020-12-18T07:41:24.166+0100")
},
{
"sender" : "Another customer",
"content" : "more content",
"time" : ISODate("2020-12-18T07:41:26.328+0100")
}
]
}

Mongoose: updating a single sub-document issues

Schema:
var educationSchema = new Schema({
schoolName: String,
startDate: Number,
endDate: Number,
degree: String,
major: String,
grade: String
});
var UserSchema = new Schema({
firstName: String,
lastName: String,
education: [educationSchema]
});
Update code:
User.findOneAndUpdate(
{"_id": req.user.id, "education._id": req.body.id},
{
"$set": {
"education.$": req.body
}
},
function(err, edu) {
}
);
Now, if the user only edits the schoolName on the UI the following happens:
Pre-save State:
{
"_id" : ObjectId("5878fb4f51ec530358fea907"),
"firstName" : "John",
"lastName" : "Doe",
"education" : [
{
"schoolName" : "ABC",
"startDate" : 1998,
"endDate" : 2005,
"degree" : "Bachelor’s Degree",
"major" : "CS",
"grade" : "3.5",
"_id" : ObjectId("5878fbb951ec530358fea909")
}
]
}
Post-save State:
"education" : [
{
"schoolName" : "XYZ"
}
]
Is $set not the right operator to use?
Updating education.$ updates the sub-document. If you want to update only the schoolName you must use education.$.schoolName.
Change your update code to:
User.findOneAndUpdate(
{"_id": req.user.id, "education._id": req.body.id},
{
"$set": {
"education.$.schoolName": req.body
}
},
function(err, edu) {
}
);
EDIT: (update any field sent through req.body)
const update = {};
Object.getOwnPropertyNames(req.body).forEach(key => {
update['education.$.' + key] = req.body[key];
});
User.findOneAndUpdate(
{"_id": req.user.id, "education._id": req.body.id},
{
"$set": update
},
function(err, edu) {
}
);

Deleting subdocuments using mongoose returning error?

I want to delete all the sub-documents of my collection.
mongoose schema :
//productSchema
var pdtSchema = new Schema({
"productId" : {type : String},
"product" : {type : String},
"item no" : {type : String},
});
var shopSchema = new Schema({
"providerId" : {type : String},
"provider" : {type : String},
"products" : [pdtSchema]
}, { collection:"shopdetails" });
module.exports.Shops = mongoose.model('Shops',shopSchema);
module.exports.Products = mongoose.model('Products',pdtSchema);
I have stored a bulk of data inside the collection and I need to delete all the products(that is the whole pdtSchema data).
code:
router.post('/delete',function (req,res) {
var providerId = req.body.providerId;
model.Shops.findById({"providerId" : providerId},function(err, doc) {
console.log(doc.products) // returns whole products here...
doc.products.remove();
doc.save(function(err,data){
res.json({"msg":"deleted"});
});
});
});
error:
(node:16351) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ValidationError: CastError: Cast to ObjectID failed for value "[Function]" at path "_id"
Use the $unset operator which deletes the products field with the findOneAndUpdate() method. Using the traditional approach of first
retrieving the document with findById() only works with a valid ObjectId, in your case you are only providing a non-ObjectId string, hence the error.
router.post('/delete',function (req,res) {
var providerId = req.body.providerId;
model.Shops.findOneAndUpdate(
{ "providerId": providerId },
{ "$unset": { "products": "" } },
{ "new": true }
function(err, doc) {
console.log(doc) // returns modified doc here...
res.json({"msg": "Field deleted"});
}
);
});
If you want to keep the array field but remove all its elements, use $set as
router.post('/delete',function (req,res) {
var providerId = req.body.providerId;
model.Shops.findOneAndUpdate(
{ "providerId": providerId },
{ "$set": { "products": [] } },
{ "new": true }
function(err, doc) {
console.log(doc) // returns doc with empty products here...
res.json({"msg": "Products deleted"});
}
);
});
This is because you are saving "providerId" in shopSchema as type String, even though it is a mongoose object.
So, comparing a string type against a mognoose ObjectId type gives a cast error.
Instead do this,
var shopSchema = new Schema({
"providerId" : {
type : Schema.ObjectId
ref : schema which they are a reference to},
"provider" : {type : String},
"products" : [pdtSchema]
}, { collection:"shopdetails" });
But, I think if providerId refers to a shop Id, then it should be _id only.
model.findById() works with _id

How to update Reference Array in mongoose

I have a Group Collection, which is having a Reference array of Members. Two Objects are inter-connected like follow. When I am adding new members to the group the members field of Group object needed to be updated. How can I do this with a mongoose update operator.
var MemberSchema = new Schema({
name:{
type:String,
default:null
},
user_id:{
type : Schema.ObjectId,
ref : 'User',
default : null
}
});
var GroupSchema = new Schema({
name:{
type:String,
default:null
},
description:{
type:String,
default:null
},
members:[MemberSchema],
},{collection:"groups"});
Thank You in advance.
Update
I added a sample document of group.
{
"_id" : ObjectId("586a2e694467c41218b302c3"),
"members" : [
{
"_id" : ObjectId("586a2e694467c41218b302c6"),
"user_id" : ObjectId("58171d75e72bf516f92dcd4e"),
"name" : "Lakmal Kapukotuwa"
},
{
"_id" : ObjectId("586a2e694467c41218b302c5"),
"user_id" : ObjectId("5821807516325e127f59438e"),
"name" : "Prasad Perera"
},
{
"_id" : ObjectId("586a2e694467c41218b302c4"),
"user_id" : ObjectId("586263515356e908de6c899a"),
"name" : "Sadun Prasad"
}
],
"description" : "Des 1",
"name" : "My group",
"__v" : 0
}
If you are sending the new members as a list of objects with the following structure e.g.
membersListToAdd = [
{
"user_id": "58171d75e72bf516f92dcd4e",
"name": "foo"
},
{
"user_id": "5821807516325e127f59438e",
"name": "bar"
}
]
then use $push with $each modifier in an update as follows:
var query = { name: 'My Group' },
options = {},
callback = function (err, result) { console.log(result); };
Group.update(query, { $push: { members: { $each: membersListToAdd } } }, options, callback)
You are doing this wrong,
no need to have links in both collections and no need to nest models
try this instead
var Group = mongoose.model("Group", new Schema({
name: {
type:String
},
description: {
type:String
},
}));
Group.virtual("users", {
ref: "User",
localField: "_id",
foreignField: "groups"
});
var User = mongoose.model("User", new Schema({
name:{
type:String
},
groups: [{
type : Schema.ObjectId,
ref : 'Group'
}]
}));

Using aggregate with populate

I am trying to use aggregate with populate. I need $group to variable of referenced ObjectId Schema. The structure is like:
var jobFilter = mongoose.Schema({
location : { type: Schema.Types.ObjectId, ref: 'Location' },
field : {type: Schema.Types.ObjectId, ref: 'Jobfield'}
})
var locationSchema = mongoose.Schema({
city : String,
longitude : Number,
latitude : Number
});
and i want to group by _field and city. I wrote this query but it did not work because of city. Is it possible to populate Location somehow in this query?
jobFilter.aggregate(
[
{
$match : {
"jobFilter.field" : {$ne: null},
"jobFilter.location" : {$ne: null}}
},
{
$group :
{ _id: {
"field" : "$jobFilter.field" ,
"location" : "$jobFilter.location.city"
}, count: { $sum: 1}}},
{
$sort : { count : -1}
}
]
)
.exec()

Resources