Related
I have two model one is productModel.js and another is reviewModel.js. I did child referencing in reviewSchema. product Schema has ratingsAverage and ratingsQuantity property. I want to manipulate these properties of properties inside from reviewModel.js. So that I have used statics method on reviewSchema.
reviewModel.js:
const Product = require("./productModel");
const { Schema } = require("mongoose");
const mongoose = require("mongoose");
const reviewSchema = new Schema({
review: {
type: String,
},
rating: {
type: Number,
min: 1,
max: 5,
},
createdAt: {
type: Date,
default: Date.now(),
},
product: {
type: mongoose.Schema.ObjectId,
ref: "Product",
required: [true, "A review must belong to a tour."],
},
user: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: [true, "A review must belong to a user"],
},
});
// Preventing from duplication of review on same tour from same user
// Combined index
reviewSchema.index({ product: 1, user: 1 }, { unique: true });
// Creating calcAverageRating() static method for calculating average rating and number of ratings on product. It should work on creating, updating and deleting of review.
reviewSchema.statics.calcAverageRating = async function (productId) {
// "this" represents here model
const stats = await this.aggregate([
{
$match: { product: productId },
},
{
$group: {
_id: "$product",
nRating: { $sum: 1 },
avgRating: { $avg: "$rating" },
},
},
]);
console.log(stats, "rrrr");
// console.log(Product, "product");
// Problem is coming here i am not able to access productModel
// const doc = await Product.findByIdAndUpdate(
// productId,
// {
// ratingsAverage: stats[0],
// ratingsQuantity: stats[0],
// },
// {
// new: true,
// runValidators: true,
// }
// );
};
// As you know static methods only call on Model so we have to think about how to call calcAverageRating() static method. problem is that we have to get this product id which one is used to creating review so we only get this id on document middleware("post") for creating and for updating and deleting we will get from get from query middleware(/^findOne/).
// Document middleware("save")
reviewSchema.post("save", function () {
this.constructor.calcAverageRating(this.product);
});
reviewSchema.post(/^findOneAnd/, async function () {
// console.log(await this.findOne());
this.r = await this.clone().findOne();
console.log(this.r, "query");
console.log(Product, "testing");
});
reviewSchema.post(/^findOneAnd/, function () {
this.r.constructor.calcAverageRating(this.r.product);
});
// reviewSchema.pre(/^find/, function (next) {
// this.populate({
// path: "product",
// select: "name",
// });
// next();
// });
// CREATING MODEL
const Review = mongoose.model("Review", reviewSchema);
// We can call here static method but we will not get productId so we have to call this static method before creating of Model.
// Review.calcAverageRating();
// EXPORTING
module.exports = Review;
productModel.js:
const mongoose = require("mongoose");
const { Schema } = require("mongoose");
const Review = require("./reviewModel");
// CREATING SCHEMA
const productSchema = new Schema(
{
name: {
type: String,
required: [true, "Please enter product name"],
unique: true,
trim: true,
},
slug: String,
price: {
type: Number,
required: [true, "A product must have a price"],
maxlength: [8, "Price cannot exceeds 8 characters"],
},
priceDiscount: {
type: Number,
validate: {
validator: function (val) {
// this only points to current doc on NEW document creation
return val < this.price;
},
message: "Discount price ({VALUE}) should be below regular price",
},
},
stock: {
type: Number,
required: [true, "Please Enter product Stock"],
maxLength: [4, "Stock cannot exceed 4 characters"],
default: 1,
},
summary: {
type: String,
required: [true, "A product must have a summary"],
},
description: {
type: String,
required: [true, "A product have a description"],
},
images: [
{
public_id: {
type: String,
required: [true, "Images public id is required"],
},
url: {
type: String,
required: [true, "Images url is required"],
},
},
],
ratingsAverage: {
type: Number,
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,
},
category: {
type: String,
required: [true, "A product must belong to a category"],
},
createdAt: {
type: Date,
default: Date.now(),
},
// ratingsAverage: {
// type: Number,
// default: 4.5,
// min: [1, "Rating must be above 1.0"],
// max: [5, "Rating must be below 5.0"],
// // Declaring custom function for do some opeartion from get value
// // set: (val) => Math.round(val * 10) / 10, // 4.666666, 46.6666, 47, 4.7
// set: (val) => Math.round(val * 10) / 10,
// },
// ratingsQuantity: {
// type: Number,
// default: 0,
// },
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
productSchema.index({ name: "text", description: "text" });
// VIRTUAL POPULATE
productSchema.virtual("reviews", {
ref: "Review",
foreignField: "product",
localField: "_id",
});
// CREATING MODEL
const Product = mongoose.model("Product", productSchema);
// EXPORTING
module.exports = Product;
I’m using Mongoose to connect with my MongoDb cluster.
My site has a logging feature. I would like these logs to deleted once they are 6 months old. To do this, I have a file that runs every day to delete documents that are more than 6 months old.
However, the deleteMany() function does not provide me with context to run a function on each document, only that every document has a specific value.
Dates are stored as numbers (shown below)
const mongoose = require('mongoose');
let Sch = new mongoose.Schema( {
id: {
type: String,
default: '',
required: true,
},
password: {
type: String,
default: '',
required: true
},
email: {
type: String,
default: '',
required: true
},
first_name: {
type: String,
required: true,
default: 'John'
},
last_name: {
type: String,
required: true,
default: 'Doe'
},
username: {
type: String,
default: '',
required: true
},
seven_shifts: {
type: Object,
default: {},
},
positouch: {
type: Array,
default: {}
},
departments: {
type: Array,
default: [],
required: true
},
locations: {
type: Array,
default: [],
required: true
},
tip_periods: {
type: Array,
default: []
},
w_4: {
type: String,
default: ''
},
employedSince: {
type: Number
},
notes: {
type: Array,
default: []
},
last_login: {
type: Number
},
});
module.exports = new mongoose.model('User', Sch, 'users');
All I need is a way to check if the number in "date" is less than the one I provide in the function
Does anybody know of a way I can delete the matching documents in one query?
Thanks.
So when I am executing my findByIdAndUpdate it doesn't execute my promise as expected and goes into my catch. I sent responses to postman and using res.json(req.user.id) and res.json(profileFields) . This is the response I get when I use
profileFields
{
"user": "5b3134a0e2543b06d130a5d7",
"handle": "wadeaston1",
"status": "Developer",
"skills": [
"HTML",
" CSS",
" Javascipt"
],
"social": {}
}
i'm at a loss here because all my fields are passing in the values as expected into user and $set. I don't understand why its going to my catch
Profile.findByIdAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(profile => res.json(profile))
.catch(err => {
res.json("Timeout");
console.log("HI");
});
Here is my Profile Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//Create Scheme
const ProfileSchema = new Schema({
user: {
//this will associate user by their ID
type: Schema.Types.ObjectId,
ref: "users"
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String
},
location: {
type: String
},
status: {
type: String,
required: true
},
skills: {
//Array of strings
type: [String],
required: true
},
bio: {
type: String
},
githubusername: {
type: String
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
fieldofstudy: {
type: String,
required: true
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
social: {
youtube: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},
instagram: {
type: String
}
},
date: {
type: Date,
default: Date.now
}
});
module.exports = Profile = mongoose.model("profile", ProfileSchema);
findByIdAndUpdate is for finding the document to update by its _id value, but you need to find the document by its user field, so you should be using findOneAndUpdate instead:
Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(...
No need to manually cast req.user.id to an ObjectId as Mongoose will do that for you based on the way user is defined in your schema.
Based on the error you gave, it looks like you need to turn req.user.id from a string to an ObjectId:
Profile.findByIdAndUpdate(
{ user: new mongoose.Types.ObjectId(req.user.id) },
{ $set: profileFields },
{ new: true }
).then( /* rest of code */
This assumes you did a const mongoose = require('mongoose') or similar.
Okay, so im getting all convensations with the following query:
return convensations.findOne({}).lean().then(function (convensations) {
console.log(convensations);
});
that would results in the following:
{ _id: 598dd4458b08b727dc53d4a6,
initiateduser: 'spillinfo',
gang: false,
global: false,
members: [ 'spillinfo', '59312d2b329b7535b07e273c' ],
name: 'no name',
__v: 0 }
thats totally fine, but when i do
var userid = "59312d2b329b7535b07e273c";
return convensations.find({members: userid}).lean().then(function (convensations) {
console.log(convensations);
});
it wont get me any results, why is that?
what im i doing wrong to check if the userid is within the members array?
UPDATE EDIT:
DB schema:
new Schema({
initiateduser : String,
name: {type:String, default: 'no name'},
members: { type: Array, default: []},
time: Number,
global: { type: Boolean, default: false},
gang: { type: Boolean, default: false},
});
and example of inserting / creating new:
var conv = new convensations();
conv.members = [userid, user2];
conv.initiateduser = userid;
conv.save(function (err,room) {
edit2:
some debug from query:
getting convensations with userid 59312d2b329b7535b07e273c
Mongoose: convensations.find({ members: ObjectId("59312d2b329b7535b07e273c") }, { fields: {} })
convensations: 0
Change your schema as,
new Schema({
initiateduser : String,
name: {type:String, default: 'no name'},
members: { type: [String], default: []},
time: Number,
global: { type: Boolean, default: false},
gang: { type: Boolean, default: false},
});
I am trying to save an new document record and some of the fields are being omitted and I have not been able to figure out why.
Here I am setting my order object
var obj = new Order(orderObj);
console.log('orderObj', orderObj);
console.log('obj', obj);
output from console.log:
orderObj { customerId: '5806e2a1759fd9ad7a1f60eb',
products:
[ { productId: '5806e7e3d0073cb4d2946aad',
customerPrice: 100,
notes: 'test',
originalPrice: 99.95,
priceOverride: true } ],
notes: 'some optional order notes',
createdBy: 'test',
total: 99.95 }
obj { customerId: 5806e2a1759fd9ad7a1f60eb,
notes: 'some optional order notes',
createdBy: 'test',
_id: 5808171e802121505e33b252,
shipped: false,
shippedDate: 2016-10-20T01:00:14.019Z,
status: 'Created, Not Shipped',
products:
[ { productId: 5806e7e3d0073cb4d2946aad,
_id: 5808171e802121505e33b253,
quantity: 1 } ] }
Here is my schema:
var orderSchema = new mongoose.Schema({
customerId: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer'},
products: [{
productId: { type: mongoose.Schema.Types.ObjectId, ref: 'Product'},
quantity: { type: Number, default: 1 },
originalPrice: { Type: Number },
customerPrice: { Type: Number },
priceOverride: { Type: Boolean, default: false },
notes: { Type: String }
}],
notes: String,
status: { type: String, default: "Created, Not Shipped" },
orderDate: { type: Date },
shippedDate: { type: Date, default: Date.now },
shipped: { type: Boolean, default: false },
total: {Type: Number, default: 0.00 },
createdBy: { type: String }
}, schemaOptions);
I cannot figure out why total and product fields (originalPrice, priceOverride) are being dropped from the mongoose Schema instance object.
Of course I figured it out right after I posted this question. The type in the Schema was listed as Type instead of type.
[this answer is for the record]
I had same kind of problem and in a schema where maxconnections and roomNo were not being saved,
I had schema
maxconnections: {type: Number | String },
roomNo: {type: Number | String },
changed it to
maxconnections: {type: Number },
roomNo: {type: String},
and now it works fine (!._.)
Also, when sending a request using postman, use content-type as JSON
Otherwise, data in fields will not get stored