My schema:
const ProductSchema = new Schema({
Category: String,
Subcategory: String,
Name: String,
Offers: [{ type: ObjectId, ref: "Offer" }]
})
const OfferSchema = new Schema({
Quantity: Number,
Images: [String],
Price: Number,
Size: String,
Color: String
})
I am doing query for products with filter offers with limit and skip. I tried this:
const products = await ProductSchema.find({ ...someFilter }).populate({
path: "Offers",
match: {
Quantity: { $gt: 2 },
Images: { $exists: true, $ne: [] }
}
}).skip(skip).limit(limit)
And I want to get only documents where length of offers is > 0. But I get documents with empty Offers. If I filter like this:
products.filter(item => item.Offers.length > 0)
My pagination will break. Can you help me?
Just require the Offers field to not be empty like so:
const products = await ProductSchema.find(
{
...someFilter,
"Offers.0": {$exists: true}
}
).populate({
path: "Offers",
match: {
Quantity: {$gt: 2},
Images: {$exists: true, $ne: []}
}
}).skip(skip).limit(limit)
Related
I am building a room booking system in nodejs. Currently I have hotels , rooms and bookings as collections.
rooms is referenced to hotels and bookings is referenced to rooms.
booking.js
const bookingSchema = new mongoose.Schema({
room: {
type: mongoose.Schema.Types.ObjectId,
ref: 'rooms'
},
start: Date,
end: Date
});
rooms.js
const roomSchema = new mongoose.Schema({
roomid: String,
hotel: {
type: mongoose.Schema.Types.ObjectId,
ref: 'hotel_managers'
},
type: String,
price: Number,
capacity: Number,
facilities: [String],
amenities: [String],
img: [String]
});
hotels.js
const hotel_manager_schema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
hotelname: {
type: String,
required: true
},
role: {
type: String,
default: 'manager'
},
location: {
type: String,
required: true
},
img:{
type: String,
required: true
}
})
N.B. This is a service provider ended system, so a hotel is basically a hotel manager with his credentials.
What i want to achieve is when a user sends a query for a given date range, I want to return all the available hotels as well as rooms in a hotel that don't have any booking in the query date range.
I am new in MongoDB so any tips or suggestions on how I can do what I want would be of great help.
Here's what you can do according to your schema model architecture; we wanna list all available hotels as well as rooms in hotels that don't have any booking at a given date range.
So to achieve this, we're gonna fetch all bookings that overlaps with date range provided in query and return their room ids; after that we fetch all rooms excluded the array of room ids returned from bookings.
const bookings = await Booking
.find({
$or: [
{ start: { $gte: from_date, $lte: to_date } },
{
end: { $gte: from_date, $lte: to_date }
},
{
$and: [{ start: { $lte: from_date } }, { end: { $gte: to_date } }]
},
],
})
.select('room');
const roomIds = bookings.map(b => b.room);
const availableRooms = await Room.find({ _id: { $nin: roomIds } })
You can extract hotel's data by populating Rooms hotel property field:
const availableRooms = await Room
.find({ _id: { $nin: roomIds } })
.populate('hotel', 'username password hotelname role location img')
I hope this would work for you.
i am expecting your database is already accumulated with some data and considering that all you have to do is just make a query in your bookingSchema.
const availableRoom = await Booking.find({ //query today up to tonight
created_on: {
$gte: new Date(2012, 7, 14),
$lt: new Date(2012, 7, 15)
}
})
Here Booking is a model. You can find details how to create model over HERE
You can find HERE how to query using dates
My mongoose schema for Recipe looks like this:
const mongoose = require("mongoose");
const { Schema } = mongoose;
const RecipeSchema = new Schema({
recipeName: {
type: String,
required: [true, "Please add a recipeName"],
maxlength: [99, "max 50 chars are allowed for the recipeName"],
},
image: {
type: String,
},
ingredients: [
{
quantity: {
type: Number,
required: true,
},
ingredient: {
type: Schema.ObjectId,
ref: "Ingredient",
},
},
],
description: [
{
type: String,
required: [true, "Please add a description"],
maxlength: [5000, "max 50 chars are allowed for the description"],
},
],
});
module.exports = mongoose.model("Recipe", RecipeSchema);
Given a list of ingredients' ids, I want to be able to find all the recipes whose ingredients list is a subset of the list I am searching by.
I tried a couple of things to no avail, like for instance given
const ingredients = [
ObjectId('614af0b845d87d639b1d337a'),
ObjectId('614b12bebfbe29d357515c63'),
]
trying to retrieve by
Recipe.find({ ingredients: {$not: { $elemMatch: { $nin: ingredients } } }})
This doesn't work because I am not taking into account the right field ingredient, but I do not know where that should be.
Given ingredients is an array with ingredients ids, which needs to be a superset of the ingredients array in the recipe, this query works:
Recipe.find({ ingredients: { $not: { $elemMatch: { ingredient: { $nin: ingredients } } } } })
Schema:
var User = new Schema({
userId: String,
name: String,
lastLogin: Date,
lastPost: Date,
followers: [String],
following: [String],
posts: [{
date: Date,
title: String,
likes: Number,
public: Boolean,
comments: [{
date: Date,
comment: String,
postedBy: String
}],
modules:[{
moduleType: String,
entries: [{
file: String,
date: Date
}]
}]
}]
});
Query:
await User.updateOne({
$and:[
{ userId: id },
{ posts: { $elemMatch: { title: activityTitle }}}
]},
{ $inc: { "posts.0.likes": 1 }}
)
.exec()
.then(() => {
console.log(`Liked activity '${activityTitle}'`)
})
This query obviously only increases the likes for the first element in posts.
But what I am trying to do is increase the likes for the post that contains the title: activityTitle.
For example a user, User1, can have 3 posts with titles, post1, post2, post3. But I want to increase the likes on post3. I have no way of knowing which post to like since when I query, it returns the whole array and not just the element with the same title.
You're close to result. You should use dot notation in your use of the $ update operator to do that:
User.updateOne({
$and:[
{ userId: id },
{ posts: { $elemMatch: { title: activityTitle }}}
]},
{ $inc: { "posts.$.likes": 1 }}
)
.exec()
.then(() => {
console.log(`Liked activity '${activityTitle}'`)
})
I have this Model:
const cart = new mongoose.Schema(
{
products: [{
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
},
quantity: {
type: Number,
required: true,
default: 1
},
title: String,
price: Number
}],
},
{ timestamps: true });
How I find all my products (from Model Product) using it.
cart = Cart.find(id);
// inside cart.products
[{productId: 'asvhbajAS13', quantity: 8 },{productId: 'asvhbajAS13', quantity: 2 }]
I want to modify all products after that, is this approach right?
What I've tried:
Product.find({
'_id': { $in: { cart.products } }
}, function(err, product) {
})
});
your code is correct but if you use findOne() .or you can use populate instead of query once more :
cart = Cart.find(id).populate("products")
This is my Mongoose Schema:
const InvoiceSchema = new Schema({
name: { type: String, required: true },
description: { type: String },
items: [{
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product'},
amount: { type: Number },
name: { type: String, required: true },
quantity: { type: Number },
rate: { type: Number, required: true }
}],
createdBy: { type: Schema.ObjectId, ref: 'User', required: true },
}
Now I want to populate my Schema from POST Datas, My problem is I don't Know how to post my items (How do I name my fields)??
I use PostMan to post Datas.
To get post data
To add a new record in mongoose
const {ObjectId} = mongoose.Schema.Types;
const newInvoice = new InvoiceSchema({
name: "John Smith",
description: "This is a description",
items: [{
product: 'THIS_IS_AN_OBJECT_ID_STRINGIFIED',
amount: 2,
quantity: 5,
//name - comes from the product model
//rate - comes from the product model
}]
});
newInvoice.save();
To POST and save it
//Response format
{
name: 'John Smith',
description: 'This is a description',
items: [
{
product: 'THIS_IS_AN_OBJECT_ID',
amount: 2,
quantity: 5
}
]
}
app.post('/yourRoute', (req, res) => {
const {name, description, items} = req.body;
const newInvoice = new InvoiceSchema({name, description, items});
newInvoice.save().then(()=>res.send('success'))
});
To bulk add items
const invoice = new Invoice();
invoice.items = req.body.items;
To add single item
invoice.items.push(item);
To update single item
const item = invoice.items.id(req.params._id);
item.attribute = ...
// Do update