How Save Nested Array into Mongodb Using Mongoose schema? - javascript

Actually, Only allFacilities field makes an error in Schema, Please Someone help by making sure the correct format of the mongoose schema allFacilities field for allFacilities array data
Actually, Only allFacilities field makes an error in Schema, Please Someone help by making sure the correct format of the mongoose schema allFacilities field for allFacilities array data
My data Look Like That
{
"name": "This is Name countru",
"type": "Hotel",
"country": "Bangladesh",
"city": "Chittagong",
"address": "22 D Block, Kolpolok Residense, Bakulia,",
"distance": "Chittagong",
"title": "tis is best hotel",
"desc": "Pamper yourself with a visit to the spa, which offers massages, body treatments, and facials. You can take advantage of recreational amenities such as an outdoor pool, a spa tub, and a sauna. Additional features at this hotel include complimentary wireless Internet access, concierge services, and a banquet hall. Grab a bite at The Exchange, one of the hotel's 3 restaurants, or stay in and take advantage of the 24-hour room service. Relax with your favorite drink at the bar/lounge or the poolside bar. Featured amenities include a business center, dry cleaning/laundry services, and a 24-hour front desk. Free valet parking is available onsite. Make yourself at home in one of the 241 air-conditioned rooms featuring LED televisions. Complimentary wireless Internet access keeps you connected, and satellite programming is available for your entertainment. Private bathrooms with separate bathtubs and showers feature hair dryers and slippers. Conveniences include phones, as well as safes and coffee/tea makers. Distances a",
"cheapestPrice": "105",
"rooms": [
"629dd3bae549560b971612da",
"629dd418e549560b971612df",
"629dd481e549560b971612ea",
"629dd4b3e549560b971612f0",
"629dd4b4e549560b971612f6",
"629dec61e549560b9716139f"
],
"photos": [
"http://res.cloudinary.com/cloudmonzu/image/upload/v1655222493/upload/jxsbi7r26cyqgnwg65ni.jpg",
"http://res.cloudinary.com/cloudmonzu/image/upload/v1655222494/upload/bybbcdb8iluy0t7smf1u.jpg",
"http://res.cloudinary.com/cloudmonzu/image/upload/v1655222493/upload/pzfzk3umv5agumt30ygo.jpg"
],
"allFacilities": [
{
"hotelfacilities": [
"dsds",
" sdsd",
" sdd"
]
},
{
"roomfacilities": [
"sdsd",
" dss",
" dss"
]
},
{
"wellnessSpa": [
"sds",
" dsd",
" sdsd",
" sds"
]
}
]
}
My Mongoose Schema Look Like That
import mongoose from "mongoose";
const HotelSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
distance: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
cheapestPrice: {
type: Number,
required: true,
},
rooms: {
type: [String],
},
photos: {
type: [String],
},
allFacilities: {
type: [String],
required: true,
},
rating: {
type: Number,
min: 0,
max: 5,
},
featured: {
type: Boolean,
default: false,
},
});
export default mongoose.model("Hotel", HotelSchema)

use "type: Array" for rooms, photos and allFacilities
name: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
distance: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
cheapestPrice: {
type: Number,
required: true,
},
rooms: {
type: Array,
},
photos: {
type: Array,
},
allFacilities: {
type: Array,
required: true,
},
rating: {
type: Number,
min: 0,
max: 5,
},
featured: {
type: Boolean,
default: false,
},
});

Related

How to use mongoose transactions with updateMany?

I am using the mongoose updateMany() method and I also want to keep it a part of transaction. The documentation shows the example of save() where I can do something like Model.save({session: mySession}) but don't really know how to use it with for example Model.updateMany()
UPDATE:
For example I have two models called SubDomain and Service and they look like this respectively:
SUB-DOMAIN
{
name: {
type: String,
required: true,
},
url: {
type: String,
required: true,
unique: true,
},
services: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Service",
},
],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
}
SERVICE:
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: { type: Number },
tags: { type: Array },
packages: [
{
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
},
],
map: { type: String },
isHidden: {
type: Boolean,
required: true,
default: false,
},
sortingOrder: { type: Number },
isForDomain: { type: Boolean, required: false, default: false },
isForSubDomain: { type: Boolean, required: false, default: false },
subDomains: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "SubDomain",
},
],
}
Now the main field here is the services field in SubDomain and subDomains field in Service.
The complicated part😅:
Whenever the user wants to create new service, I want to $push that service's _id into the array of services of all the subDomains inside that new service
And for that, I am using the updateMany() like this:
const sess = await mongoose.startSession();
sess.startTransaction();
const newService = new Service({
_id: mongoose.Types.ObjectId(),
subDomains: req.body.subDomains
...foo
})
await SubDomain.updateMany(
{ _id: { $in: req.body.subDomains } },
{ $push: { services: newService._id } }
);
The problem starts here, of course I can do:
newService.save({session: sess})
but how do I keep my SubDomain's updateMany in the same transaction (i.e sess)
I know my example is difficult to wrap your head around but I have tried to pick a simplest example rather than copying the exact same code which would have been a lot more difficult

Mongoose Automatically Decreases Field with Type of Number

i have used mongoose for my project currently, and this is my Schema:
const mongoose = require('mongoose');
const classSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
consultant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Consultant',
required: true,
},
faculty: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Faculty',
required: true,
},
startYear: {
type: String,
required: true,
},
currentSchoolYear: {
type: String,
required: true,
},
currentSemester: {
type: String,
required: true,
},
classname: {
type: String,
required: true,
unique: true,
},
classSize: {
type: Number,
required: true,
},
warnedLength: {
type: Number,
required: true,
},
});
const Class = mongoose.model('Class', classSchema);
module.exports = Class;
as you can see, i have 2 properties are classSize and warnedLength are Number. Now i want to make a function that when i onClick a button from the client, the value of classSize and warnedLength will automatically decrease by 1. is there anyway to do that, thank you so much for help me out, it means a lot to me, have a good day

How to optimize performance with CREATE, PUT, and DELETE requests on MongoDB?

I have a database named "reviews" with a 9.7GB size. It has a collection name products. I was able to optimize the READ request using indexing technical by running the command db.products.ensureIndex({product_name: 1}); When I run the following command db.products.find({product_name:"nobis"}).explain("executionStats"); in MongoDB terminal, it shows that my execution time reduces from 28334ms to 3301ms.
I have the following 2 questions:
1) How do I use explain("executionStats"); on CREATE, PUT and DELETE requests? For example, I got this following error [thread1] TypeError: db.products.insert(...).explain is not a function when I tried to use the following insert function
db.products.insert({"product_id": 10000002,"product_name": "tissue","review": [{"review_id": 30000001,"user": {"user_id": 30000001,"firstname": "Peter","lastname": "Chen","gender": "Male","nickname": "Superman","email": "hongkongbboy#gmail.com","password": "123"},"opinion": "It's good","text": "It's bad","rating_overall": 3,"doesRecommended": true,"rating_size": "a size too big","rating_width": "Slightly wide","rating_comfort": "Uncomfortable","rating_quality": "What I expected","isHelpful": 23,"isNotHelpful": 17,"created_at": "2007-10-19T09:03:29.967Z","review_photo_path": [{"review_photo_id": 60000001,"review_photo_url": "https://sdcuserphotos.s3.us-west-1.amazonaws.com/741.jpg"}, {"review_photo_id": 60000002,"review_photo_url": "https://sdcuserphotos.s3.us-west-1.amazonaws.com/741.jpg"}]}, {"review_id": 30000002,"user": {"user_id": 30000002,"firstname": "Peter","lastname": "Chen","gender": "Male","nickname": "Superman","email": "hongkongbboy#gmail.com","password": "123"},"opinion": "It's good","text": "It's bad","rating_overall": 3,"doesRecommended": true,"rating_size": "a size too big","rating_width": "Slightly wide","rating_comfort": "Uncomfortable","rating_quality": "What I expected","isHelpful": 23,"isNotHelpful": 17,"created_at": "2007-10-19T09:03:29.967Z","review_photo_path": [{"review_photo_id": 60000003,"review_photo_url": "https://sdcuserphotos.s3.us-west-1.amazonaws.com/741.jpg"}]}]}).explain("executionStats");
2) Is there any performance Optimization method I can use for the CREATE, PUT and DELETE requests? For example, I am able to use POSTMAN to get the response time of a DELETE request, but the response time takes 38.73seconds.
const deleteReview = (request, response) => {
const id = parseInt(request.params.id);
Model.ProductModel.findOneAndDelete({ "review.review_id": id}, (error, results) => {
if (error) {
response.status(500).send(error);
} else {
response.status(200).send(results);
}
});
};
This is my MongoDB schema:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/reviews', { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true });
const Schema = mongoose.Schema;
const productSchema = new Schema({
product_id: { type: Number, required: true, unique: true },
product_name: { type: String, required: true, unique: true },
review: [{
review_id: { type: Number, required: true, unique: true },
user: {
user_id: { type: Number },
firstname: { type: String },
lastname: { type: String },
gender: { type: String, enum: ['Male', 'Female', 'Other'] },
nickname: { type: String },
email: { type: String, required: true },
password: { type: String, required: true },
},
opinion: { type: String, required: true },
text: { type: String },
rating_overall: { type: Number, min: 1, max: 5, required: true },
doesRecommended: { type: Boolean, required: true },
rating_size: { type: String, enum: ['a size too small', '1/2 a size too small', 'Perfect', '1/2 a size too big', 'a size too big'], required: true },
rating_width: { type: String, enum: ['Too narrow', 'Slightly narrow', 'Perfect', 'Slightly wide', 'Too wide'], required: true },
rating_comfort: { type: String, enum: ['Uncomfortable', 'Slightly uncomfortable', 'Ok', 'Comfortable', 'Perfect'], required: true },
rating_quality: { type: String, enum: ['Poor', 'Below average', 'What I expected', 'Pretty great', 'Perfect'], required: true },
isHelpful: { type: Number, required: true, default: 0 },
isNotHelpful: { type: Number, required: true, default: 0 },
created_at: { type: Date, required: true },
review_photo_path: [{
review_photo_id: { type: Number },
review_photo_url: { type: String }
}]
}]
});
const ProductModel = mongoose.model('product', productSchema);
module.exports = { ProductModel };
If you do not have one, ensure you have an index of review.review_id on your products collection. You're using that to look up what to delete so it should be indexed.
I read your deleteReview function as deleting the product document that contains the review, not just removing the individual review -- is that what you expect?
You should be able to just $pull the review from the reviews array to get rid of it.
You can use explain on an update like so:
db.products.explain().update({...}, {...});
See: https://docs.mongodb.com/manual/reference/method/db.collection.explain/
You can explain:
aggregate()
count()
find()
remove()
update()
distinct()
findAndModify()

MongoDB data modelling performance

I'm currently trying to figure out at mongodb what's the best way in terms of performance cost and redundancy the best way of building a big document data schema. The final JSON from my rest -> app will be likely how it is structured.
Now internally the data will not be used as many to many that's why i binded it into a single document. Only the id will be used as a reference in another collections.
What you guys think, is it better to spit as relational way, with multiple collection to store the content inside of deliverable and use reference or just embedded. (since NoSQL has no joins i though this way will speed up)
Current using mongoose at node app
The Schema:
projectSchema = new Schema({
name: {
type: String,
required: true,
minlength: 3,
maxlength: 50
},
companyId: {
type: mongoose.Types.ObjectId,
ref: 'companies',
required: true
},
deleted: {
type: Number,
enum: [0, 1],
default: 0
},
predictedStartDate: {
type: Date,
default: ""
},
predictedEndDate: {
type: Date,
default: ""
},
realStartDate: {
type: Date,
default: ""
},
realEndDate: {
type: Date,
default: ""
},
//not final version
riskRegister: [{
name: String,
wpId: {
type: mongoose.Types.ObjectId,
ref: 'projects.deliverables.workPackages.id',
required: true
},
probability: String,
impact: String,
riskOwner: String,
response: String,
duration: String,
trigger: String,
status: String,
plannedTimming: String
}],
deliverables: [{
body: String,
workPackages: [{
body: String,
activities: [{
body: String,
tasks: [{
content: String,
properties: [{
dependecies: Array,
risk: {
type: Number,
enum: [0,1],
required: true
},
estimatedTime: {
type: Number,
required: true
},
realTime: {
required: true,
default: 0,
type: Number
},
responsible: {
id: {
type: Number,
default: -1
},
type: {
type: String,
enum: [0, 1], //0 - user, 1 - team
default: -1
}
},
materialCosts: {
type: Number,
default: 0
},
status: {
type: Number,
default: 0
},
approval: {
type: Number,
default: 0
},
startDate: {
type: Date,
default: ""
},
finishDate: {
type: Date,
default: ""
},
endDate: {
type: Date,
default: ""
},
userStartDate: {
type: Date,
default: ""
},
endStartDate: {
type: Date,
default: ""
},
taskNum: {
type: Number,
required: true
},
lessonsLearn: {
insertedAt: {
type: Date,
default: Date.now
},
creatorId: {
type: mongoose.Types.ObjectId,
ref: 'users',
required: true
},
situation: {
type: String,
required: true
},
solution: {
type: String,
required: true
},
attachments: Array
}
}]
}]
}]
}]
}]
})
The only concern I would raise would be regarding deliverables. If in the future there is a use case to do some CRUD operation regarding activities or tasks on the workPackage, the mongodb position operator $ does not support inner arrays, so you would be forced to extract all the deliverables and in memory iterate over all and only after update the deliverables.
My sugestion would be to support only arrays in the first level on the object. The inner objects should be moduled in separate collection ( activities and tasks ). In latest versions of mongodb you now have support to transactions so you can implement ACID on your operations against database, so the manipulation of all this information can be done in an atomic way.

Simple Schema error in Meteor

I am using the meteor accounts and simple schema for users to register and enter their profile information in my app. I defined a schema for users and attached a schema for address to it. However, when I go to register an account, I keep getting the error "Address required" although I filled out all the required fields for address. Here's my schema:
Schemas.UserAddress = new SimpleSchema({ //UserAddress schema defined
streetAddress: {
type: String,
max: 100,
optional: false
},
city: {
type: String,
max: 50,
optional: false
},
state: {
type: String,
regEx: /^A[LKSZRAEP]|C[AOT]|D[EC]|F[LM]|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEHINOPST]|N[CDEHJMVY]|O[HKR]|P[ARW]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY]$/,
optional: false
},
zipCode: {
type: String,
regEx: /^[0-9]{5}$/,
optional: false
}
});
var Schemas = {};
Schemas.UserProfile = new SimpleSchema({
companyName: {
type: String,
regEx: /^[a-zA-Z-]{2,25}$/,
optional: false
},
tireMarkup: {
type: Number,
optional: true,
min: 1
},
phoneNum: {
type: String,
regEx: /^[(]{0,1}[0-9]{3}[)]{0,1}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{4}$/,
optional: false
},
confirmed: {
type: Boolean,
optional: true
},
});
Schemas.User = new SimpleSchema({
emails: {
type: [Object],
optional: false
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schemas.UserProfile,
optional: false
},
address: { //Attach user address schema
type: Schemas.UserAddress,
optional: false
},
services: {
type: Object,
optional: true,
blackbox: true
}
});
Meteor.users.attachSchema(Schemas.User);
Here is my accounts config which creates the sign up form:
Meteor.startup(function () {
AccountsEntry.config({
logo: '', // if set displays logo above sign-in options
termsUrl: '/terms-of-use', // if set adds link to terms 'you agree to ...' on sign-up page
homeRoute: '/', // mandatory - path to redirect to after sign-out
dashboardRoute: '/dashboard/', // mandatory - path to redirect to after successful sign-in
profileRoute: '/profile',
passwordSignupFields: 'EMAIL_ONLY',
showOtherLoginServices: true, // Set to false to hide oauth login buttons on the signin/signup pages. Useful if you are using something like accounts-meld or want to oauth for api access
extraSignUpFields: [
{
field: "companyName",
label: "Company Name",
placeholder: "Petrocon",
type: "text",
required: true
},
{
field: "firstName",
label: "First Name",
placeholder: "John",
type: "text",
required: true
},
{
field: "lastName",
label: "Last Name",
placeholder: "Nguyen",
type: "text",
required: true
},
{ field: "streetAddress",
label: "Street Address",
placeholder: "12345 Main Street",
type: "text",
required: true
},
{ field: "city",
label: "City",
placeholder: "Springfield",
type: "text",
required: true
},
{ field: "state",
label: "State",
placeholder: "Missouri",
type: "text",
required: true
},
{ field: "zipCode",
label: "Zip Code",
placeholder: "65801",
type: "text",
required: true
},
{
field: "phoneNum",
label: "Contact Number",
placeholder: "316-000-0000",
type: "text",
required: true
}
]
});
});
As you can see, I defined all of the fields in the address schema in AccountsEntry.config.. therefore I don't know why when I enter all the information in the form, I get the error 'address required'. Does anyone know what's going on? Thank you in advance!
Looks like you're using the accounts-entry package. You can see the code where the account is created in this file:
https://github.com/Differential/accounts-entry/blob/9aac00cb3c67afcbb1cc990c7af1f2c7607a2337/server/entry.coffee
Line 29 looks like this:
profile: _.extend(profile, user.profile)
If you debug and look at the value of profile after the extend method is called, you'll see this:
{
"companyName": "Petrocon",
"firstName": "John",
"lastName": "Nguyen",
"streetAddress": "12345 Main Street",
"city": "Springfield",
"state": "Missouri",
"zipCode": "65801",
"phoneNum": "316-000-0000"
}
There is no property named "address" for your Schemas.User schema.
There might be some slick way to do what you're looking for, but the easiest approach is to just get rid of the Schemas.UserAddress schema. Move those properties (streetAddress, city, state, zipCode) into the Schemas.UserProfile schema and it will work.

Categories