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
Related
I have a Shop Model
const Shop = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
shop_name: { type: String },
products: {_id: mongoose.Schema.Types.ObjectId,type:Array},
});
and a product schema
const Product = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: { type: String },
description: { type: String },
shop: { type: mongoose.Schema.Types.ObjectId, ref: "Shop" },
});
I'm trying to access a product within the products array of the Shop model, so that I can update it.
I've looked online a lot but couldn't quite find what I'm looking for. I need to access a very specific product within the products array with the given parameters, which are the id of the shop and the id of the product.
This is what I tried to do
const item = await Product.findOne({_id} , 'products').find({"products._id" : productId})
But what this does is it gives a mongoose object if the second find method hits a match
[
{
products: [ [Object] ],
_id: 617f1bca39a5a43c1a981060,
butik: 'scsbutik',
butik_slug: 'egzbutikcom-1000010',
butik_image: 'https://webizade.com/bm/img/butik-10.jpg',
butik_points: '9.8',
butik_order_count: 45,
butik_success_order_count: 42,
butik_refund_count: 3,
is_butik_refund: true,
__v: 0,
login: []
}
]
I need to access the object INSIDE the products array and update that product.
Appreciate any help in advance.
don't use by default _id format I suggest declare a different value and then using populate method you can do it
const Product = mongoose.Schema({
shopId: mongoose.Schema.Types.ObjectId,
title: { type: String },
description: { type: String },
shop: { type: mongoose.Schema.Types.ObjectId, ref: 'Shop' },
});
THEN ROUTING
const item = await Product.find(_id).populate('shopId')
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")
I'm trying to achieve something equivalent to a conditional JOIN query, but then with GraphQL.
I'm using Mongoose for my db model and MongoDB as database.
I'll illustrate my problem with the following graphQL schema:
type Booking {
_id: ID!
client: Client!
rooms: Room!
activities: Activity!
nrOfAdults: Int!
arrivalDate: String!
departureDate: String!
}
type Room {
_id: ID!
name: String!
contents: String
priceNight: Float!
maxAdults: Int!
reservations: [Booking]
}
The Mongoose schema:
const bookingSchema = new Schema(
{
client: {
type: Schema.Types.ObjectId,
ref: 'Client'
},
rooms: [{
type: Schema.Types.ObjectId,
ref: 'Rooms'
}],
nrOfAdults: {
type: Number,
required: true
},
arrivalDate: {
type: Date,
required: true
},
departureDate: {
type: Date,
required: true
}
},
{ timestamps: true }
);
const roomSchema = new Schema({
name: {
type: String,
required: true
},
priceNight: {
type: Number,
required: true
},
maxAdults: {
type: Number,
required: true
},
reservations: [
{
type: Schema.Types.ObjectId,
ref: 'Booking'
}
]
});
I can query rooms, for example, if I want to get the rooms for 3 or more adults I run:
Room.find({
maxAdults: { $gte: 3 }
});
This works fine.
However, I'd also like to show the available rooms, which means I need to impose a condition on the booking objects which are hold in reservation.
I thought this would be fairly easy, using something like:
Room.find({
maxAdults: { $gte: 3 },
reservations: { $elemMatch: { arrivalDate: { $gte: *some date*}}}
});
But it returns an empty array, while it should return some value, based on the data in mongodb:
To make things a little more clear, I'd like to achieve the same outcome as the following SQL query would give me:
SELECT *
FROM room
JOIN booking ON room.id = booking.roomId
WHERE
room.maxAdults >= 3
AND
(
booking.arrivalDate > CAST('2020-05-15' AS DATE)
OR
booking.departureDare < CAST(2020-05-06' AS DATE)
)
Assuming that you have saved the values similar to what you have mentioned in the mongoose schema.
Explore the how to do join in mongodb. Aim is to do the join before executing the query on the sub fields from the different collection.
Relevant Answer: How do I perform the SQL Join equivalent in MongoDB?
I suggest using aggregate pipeline for accomplishing what you want.
Suggested code :
Room.aggregate([
{
$match: {
maxAdults: { $gte: 3 }
}
},
{
$lookup: {
from: "bookings",
localField: "reservations",
foreignField: "_id",
as: "booking"
}
},
{
$unwind: '$booking'
},
{
$match: {
booking.arrivalDate: { $gte: *some date* }
}
},
])
This is the relevant portion of my Schema:
var classroomSchema = mongoose.Schema({
students: [{
_id: mongoose.Schema.Types.ObjectId,
ref: 'User',
rate: {
type: Number,
default: 200,
},
referrals: [mongoose.Schema.Types.ObjectId],
}],
)};
Here rate and referrals are properties of the students which are valid in the context of that classroom, and cannot be populated from the Students model.
Is there any way to define my schema such that I can keep those fields(rate and referrals) and also use populate to link other fields such as name, age, etc of the student?
Change your schema to this:
var classroomSchema = mongoose.Schema({
students: [{
rate: { type: Number, default: 200 },
user: { ref: 'User', type: Schema.Types.ObjectId },
referrals: [mongoose.Schema.Types.ObjectId],
}],
});
Usage:
classroom
.findOne(...)
.populate('user')
.exec((err, classroom) => {
let student0 = classroom.students[0];
// student0.rate
// student0.user.name
});
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