Im having issues populating my mongoDB collection with another collection based off the _id. It Keeps returning an empty object with no errors or anything?
Property Schema
const PropertySchema = new Schema({
landlord: {
type: Schema.Types.ObjectId,
ref: "Landlord",
required: true,
},
...
});
Landlord Schema
import { Schema as _Schema, model } from "mongoose";
const Schema = _Schema;
const LandlordSchema = new Schema({
fname: {
type: String,
required: true,
},
lname: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
company: {
type: String,
},
});
const Landlord = (module.exports = model("Landlord", LandlordSchema));
export function get(callback, limit) {
Landlord.find(callback).limit(limit);
}
Property Controller
exports.readProperty = async (req, res) => {
await Property.find({ _id: req.params.propertyId })
.populate({
path: "Landlord",
select: "fname lname email phone company",
model: "Landlord",
strictPopulate: false,
})
.then(function (err, property) {
if (err) return res.send(err);
res.json(property);
});
};
mongodb Property Collection
Mongodb Landlord Collection
When running the get call from postman it returns:
I fixed this issue by selecting the field: landlord not Landlord
Related
this is my schema for storing products using mongoose as below.
const mongoose = require("mongoose");
const mongoosePaginate = require("mongoose-paginate-v2");
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
productImage: {
type: String,
required: true,
},
description: {
type: String,
},
createdAt: {
type: Date,
default: new Date(),
},
deletedAt: {
type: Date,
},
});
productSchema.plugin(mongoosePaginate);
const productModel = mongoose.model("Product", productSchema, "Product");
module.exports = productModel;
and this how I have the schema for storing categories that products are related to
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
});
const categoryModel = mongoose.model("Category", categorySchema, "Category");
module.exports = categoryModel;
What I don´t know is how to populate my controller.
getAll: async (req, res) => {
const limitPage = parseInt(req.query.limit, 10) || 10;
const pageChange = parseInt(req.query.page, 10) || 1;
Product.paginate({}, { limit: limitPage, page: pageChange })
.then((result) => {
return res.status(200).json({
message: "GET request to all getAllProducts",
dataCount: result.length,
result: result,
});
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
},
Please help, I don´t understand why it not being populated and how to see the categories displayed with the categorie they belong to.
You should probably include populate in your query like so:
...
Product.paginate({}, { limit: limitPage, page: pageChange }).populate('category')
...
Note: Are you sure you want to have a 1-1 relation between products and categories. Because this is what you achieve if you set the relation like you did on both schemas. If yes, you should find a way to ensure that this 1-1 relation is enforced each time you save or update objects.
I'm trying to find out the way to remove nested object in one collection once the document from another collection is expired
LocationsSchema.js
const mongoose = require('mongoose');
const locationsSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please add a location name (string)']
},
confirmedBookings: [
{
startDate: {
type: Number
},
finishDate: {
type: Number
}
}]
}, {
timestamps: true
})
module.exports = mongoose.model('Locations', locationsSchema)
BookingsSchema.js
const mongoose = require('mongoose');
const Location = require('./locationModel');
const bookingSchema = mongoose.Schema({
startDate: {
type: Number,
required: [true, 'Please add a valid Date']
},
finishDate: {
type: Number,
> timestamp
required: [true, 'Please add a valid Date'],
index: true
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: Location
}
}, {
timestamps: true
})
bookingSchema.index({finishDate: 1}, {expireAfterSeconds: 0})
module.exports = mongoose.model('Booking', bookingSchema)
This is how I delete the object manually in
BookingsController.js
const deleteBookings = asyncHandler(async (req, res) => {
const booking = await Booking.findById(req.params.id);
if (!booking) {
res.status(400);
throw new Error('Booking not found');
}
await Location.findOneAndUpdate({_id: booking.location},
{$pull: {'confirmedBookings': {_id: req.params.id}}});
await booking.remove();
res.status(200).json({id: req.params.id});
})
But I also want to be able to delete the objects ones theirs finishDate are before the present time.
I tried to create an TTL index for that but it seems it doesn't work in the way I did it
I found this on the documentation for mongoose:
Subdocuments have save and validate middleware just like top-level
documents. Calling save() on the parent document triggers the save()
middleware for all its subdocuments, and the same for validate()
middleware.
But that hasn't been working for me. when I call save on my parent, the subdocument doesn't get created in its own collection. Here's my code:
Cart Model
const mongoose = require("mongoose");
const cartSchema = new mongoose.Schema({
numOfSessions: {
type: Number,
required: true
},
status:{
type: String,
enum: ["completed", "active", "deleted"],
required: true
}
}, { timestamps: true, versionKey: false });
const Cart = mongoose.model('shoppingCart', cartSchema);
module.exports = Cart;
User Model
const mongoose = require("mongoose");
const Cart = require("./xxxx").schema
const Schema = mongoose.Schema;
const userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true
},
shoppingCarts: [ Cart ]
}, { timestamps: true, versionKey: false });
const User = mongoose.model('user', userSchema);
module.exports = User;
Server Side
const new_user = new User({
firstName: req.body.firstname,
lastName: req.body.lastname,
username: req.body.username,
phoneNum: req.body.phone,
userType: req.body.userType,
email: req.body.email,
password: hashedPassword
});
new_user.shoppingCarts.push(new_cart);
console.log('pushed')
new_cart.save(); //If i take out this line, this subdocument doesn't get saved
new_user.save()
.then((result) => {
console.log(result);
});
To save the subdocument, I'm having to call save on it them well. Is this how it's supposed to be? Thx :D
I am using MongoDB and Mongoose.
Suppose I have the following Schema.
const notificationMetaSchema = new mongoose.Schema({
listingId: { type: mongoose.Schema.Types.ObjectId },
});
const notificationSchema = new mongoose.Schema({
category: { type: String, required: true, enum: [ "categoryA", "categoryB" ] },
meta: notificationMetaSchema,
});
I want my "listingId" field to be required only when the "category" field is "categoryA".
This validation ideally exists during both document creation and updates.
How do I construct a custom validator to achieve this effect?
EDIT
I have tried the following:
const notificationSchema = new mongoose.Schema({
category: { type: String, required: true, enum: [ "categoryA", "categoryB" ] },
meta: {
listingId: {
type: mongoose.Schema.Types.ObjectId,
required: function () {
return [
"categoryA",
].includes(this.category);
}
},
},
});
However, when I call the following query:
Notification.findOneAndUpdate({}, $set: { category: "categoryA", meta: {} }).exec();
No validation error is thrown
You can write a javaScript function for a field in mongoose schema, that function can act as custom validator, Your schema should look like :
const notificationSchema = new mongoose.Schema({
category: {
type: String,
required: true,
enum: ["categoryA", "categoryB"]
},
meta: {
listingId: {
type: mongoose.Schema.Types.ObjectId,
required: function checkRequiredOrNot() {
/** This function returns true or false, 'this.category' will retrieve current object's 'category' value */
return this.category == "categoryA" ? true : false;
}
}
}
});
I have two models, with a many-to-few relationship, that I'm modelling as follows:
// Portfolio
const portfoliosSchema = new Schema({
name: { type: String, required: true },
description: { type: String },
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
positions: [{
stock: { type: Schema.Types.ObjectId, ref: 'Stock', required: true },
cost: number,
amount: number,
}]
});
// Stock
const stocksSchema = new Schema({
exchange: { type: String, required: true },
symbol: { type: String, required: true },
company: { type: String },
description: { type: String }
});
Without writing a custom service / in a feathers friendly way, how would I:
Query portfolios and populate the relevant records from the stocks
collection
Simplify insert/updates to the nested positions within the portfolio schema (ie without updating the entire record)
Is this supported / should I write a custom service and/or normalize the relationship?
Edit - Solved #1 the first issue of getting extra data using a before hook:
function(hook) {
const query = hook.params.query;
hook.params.query = Object.assign({},query,{
$populate: {
path: 'positions.stock',
select: 'exchange symbol'
}
});
}
Sample of populate code, adjust to your needs:
Portfolio.find({ some: 'params' })
.populate({ path: 'stock', select: 'name -_id' })
.exec((err, portfolios) => {
res.json({ portfolio: portfolios });
});
Updating a nested array item:
Position.update({ 'position._id': 'h43q9h94945d948jh098j6h0' }, {
'$set': { 'position.$.whatever': 'your-updated-stuff' }
}, err => {
if (err) return console.log(err));
res.json({ success: true });
});