How to write update query in mongodb for deeply nested array? - node.js

Hi I have a Model Customer and its schema
var customerSchema = new Schema({
name: {type: String, required:true, trim: true, index: true, default: null, sparse: true},
cardInfo: { type: [cardInfoSchema]}
})
var cardInfoSchema = new Schema({
customerId : { type: String, required: true, index: true, unique: true,trim : true, sparse: true},
cards: { type:[cardsSchema], default:[]}
}, {_id: false});
var cardsSchema = new Schema({
cardType : { type: String, required: true, default: null, trim : true },
isActive : { type: String, required: true, trim: true }, //0: not active, 1: active
cardId : { type: String, required: true, trim: true },
createdAt : { type: Date, default: Date.now, required: true }
})
I want to add multiple cards of customer so I am using this
var dataToSet = {
'cardInfo.customerId': '25934285649875',
$push: {
'cardInfo.cards': {
cardId: 'somecardid,
cardType: 'type',
createdAt: new Date().toISOString(),
isActive: true
}
}
};
But I am getting this error.
cannot use the part (cardInfo of cardInfo.customerId) to traverse the element ({cardInfo: []})
Please help me in writing the query to add card of customer using mongodb or mongoose.

Try the positional $ operator in your update which acts as a placeholder for the first element that matches the query document, and when you use it make sure the cards array field must appear as part of the query document. In your case you'd want to add a card document into the 'cards' array, but only if the cardId doesn't exist:
var query = {
"cardInfo.cards.cardId": { "$nin": ["somecardid"] }
};
var update = {
"$push": {
"cardInfo": { "customerId": "25934285649875" },
"cardInfo.$.cards": {
cardId: "somecardid",
cardType: "type",
createdAt: new Date().toISOString(),
isActive: true
}
}
};
Customer.update(query, update, function (err, result) { ... });

Related

Find matched data from object in mongoose

I want to get all matched data from an object but I am getting an empty array.
Here is the location table:
const locationSchema = new mongoose.Schema(
{
location: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
},
{
timestamps: true,
}
);
and it is embedded in route table:
const routeSchema = new mongoose.Schema(
{
location: {
from: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
to: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
date: {
type: String,
required: true,
},
departureTime: {
type: Number,
required: true,
},
arrivalTime: {
type: Number,
required: true,
},
},
{
timestamps: true,
}
);
Now I am running query to get the matched data from route table but I am getting an empty array.
http://127.0.0.1:3000/trips?from=6295871d69217e9c28cf7f19&to=6295874869217e9c28cf7f1c&date=2022-06-02
here is the query :
router.get("/trips", async (req, res) => {
if (!req.query.from || !req.query.to || !req.query.date) {
return res.send({
error: "Please enter the data to get the trip",
});
}
const { from, to, date } = req.query;
const routes = await Route.find({
from,
to,
date,
});
Another Question:
I am passing an Id as a value now I want to pass value as a sting like this: from=Mumbai&to=Ahmedabad&date=2022-06-02.
How to do that? because whenever I do that I am getting a casting error
I suggest you to change the location schema to have from and to locations separately like below.
const locationSchema = new mongoose.Schema(
{
fromLocation: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
toLocation: {
name: {
type: String,
unique: true,
required: true,
lowercase: true,
},
subLocation: [String],
},
},
{
timestamps: true,
}
);
Thus the route schema should look like this
const routeSchema = new mongoose.Schema(
{
location: {
type: mongoose.Schema.Types.ObjectId,
ref: "Location",
required: true,
},
date: {
type:String,
required: true
},
....
....
And then do something like this...
let locations = await Location.find({
'fromLocation.name': from,
'toLocation.name': to,
});
After that
const ids = locations.map(location => location._id)
const routes = await Route.find({$and: [{location : {$in: ids}},{date}]});
const route = routes.find(()=>{
return ([{ date }, { routes }])
});

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 } };

Calculating the length of a schema and storing it in the data base

I am using node.js express.js and mongoose to develop my back end, I have this mongoose schema where I want to add a field called NumberRecords for every stored document this field will have the length value of the array csvData, I looked around some similar question here and I found I can use this pre function which I did but I get nothing on my database no field called NumberRecords is being added.
How do I fix this?
const rowSchema = new mongoose.Schema({
SESSION_ID: {
type: String,
required: false,
},
CARD_NUMBER: {
type: String,
required: false,
},
TERMINAL_ID: {
type: String,
required: false,
},
EXTERNAL_STAN: {
type: String,
required: false,
},
})
const csvSchema = new mongoose.Schema(
{
fileName: { type: String, required: true },
csvData: { type: [rowSchema], required: true },
NumberRecords: { type: Number, required: true },
},
{
timestamps: true,
}
);
csvSchema.pre("validate", function (next) {
this.NumberRecords = this.csvData.length;
next();
});
module.exports = mongoose.model("csvRecords", csvSchema);

How to select a value from an array in mongoose schema

Using MongoDb version 3.2.7
I have a mongoose schema like this which has an array of stock in branch schema. I want to select a subCategoryId in stock array and get the currentPrice of that subCategoryId only, for that I am using query
var getCriteria = { "stock.subCategoryId": subCategoryId }
var update = { "stock.$.currentPrice": currentPrice }
This query works for me at the time of updating the value as I am able to update the currentPrice of selected subCategoryId perfectly. But when I want to get a price of particular subCategoryId the following query gets me all the stocks in the branch collection. The query I am using is this:
var getCriteria ={ "stock.subCategoryId": subCategoryId }
Mongoose Schema
var branch = new Schema({
branchName: { type: String, trim: true, index: true, default: null },
isBlocked: { type: Boolean, default: false, required: true },
email: { type: String, trim: true, required: true, unique: true, index: true },
password: { type: String, required:true },
accessToken: { type: String, trim: true, index: true, unique: true, sparse: true },
stock: [stock],
});
var stock = new Schema({
categoryId: { type:Schema.ObjectId, ref: "categoies", default: null },
subCategoryId: { type:Schema.ObjectId, ref: "subCategories", default: null },
currentPrice: { type: Number },
isBlocked: { type: Boolean, default: false, required: true },
Date: { type: Date, default: Date.now, required: true }
});
To retrieve only the matching array element try this:
branch.find(getCriteria,{'stock.$' : 1},function(err,branch){...});
stock.$ will help you to retrieve only the matched element from the array.

Mongoose - reference an embedded id in the parent document

I have this simple schema so far:
var room = new Schema(
{
name: { type: String, default: null, trim: true }
});
var event = new Schema({
name: { type: String, default: null, trim: true },
startDate: Date,
endDate: Date,
logo: { type: Boolean, default: false },
public: { type: Boolean, default: false },
rooms: [room]
sessions: [
{
title: { type: String, default: null, trim: true },
description: { type: String, default: null, trim: true },
date: Date,
start: Number,
end: Number,
room: { type: Schema.Types.ObjectId, ref: 'room' }
}
]
});
I know how to reference another collection but how do I reference an embedded id in the parent document?
I know this schema is not right because even If I delete a room, the room reference is not removed from a session where it is referenced.
Thanks in advance!
You could create a reference to the event in room schema.Then use the schema.pre middleware to remove the sessions.room value whenever you do a remove on the main parent room.(make sure you remove the eventid from main room schema as well).Also refer Removing many to many reference in Mongoose
var room = new Schema({
name: {
type: String,
default: null,
trim: true
},
eventid: {
type: Schema.Types.ObjectId, //Set reference to event here.
ref: 'event'
}
});
room.pre('remove', function(next) {//event is the schema name.
this.model('event').update({; //this will have all the models,select the event
sessions.room: this._id//will have the room id thats being deleted
}, {
$pull: {
sessions.room: this._id//removes that array from the event.sessions.room
}
}, {
multi: true
},
next();//continues and completes the room.remove.
);
});

Resources