i have a problem updating field and push object on the same document in one action.
this is my simple schema looks like
var Schema = new schema({
shopName: String,
address: String
products: [productSchema]
})
var productSchema = new schema({
productName: String,
ingredients: String,
item: {
qty: {type: Number, default: 0},
carted: [
{
cartId: String,
timestamp: {type: Date, default: Date.now}
}
]
}
})
the illustration is when i add cart for a product, then i will subtract the product quantity with quantity order, and also push cart info to the 'carted' array field.
i've found that "$inc": {"products.$.item.qty": -req.body.orderQty} can subtract the quantity, but it only runs on findOneAndUpdate query.
so, is there an efficient way to handle that case?
ok just tried this, and solved my problem
productModel.update({'products._id' : productID},
{
"$inc": {"products.$.item.qty": -req.body.cartQty},
"$push": {"products.$.item.carted": {cartId: req.body.cartId, qty: req.body.cartQty}}
},function(err, docs){
if (err){
console.log(err)
}else{
console.log(docs)
}
})
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
I currently have a schema:
var User = new Schema({
id: String,
position: [{
_id:String,
title: String,
location: String,
start: String,
term:Number,
description:String,
date: {type: Date, default: Date.now},
applied:[{
candidate_id: String,
_id:String
}],
}]
I'm trying to insert data into the 'applied' subdocument but cant seem to get it working.
my function:
app.post('/apply',function (req,res){
//hard coded for testing purposes
User.update({id:mongoose.Types.ObjectId("58c2871414cd3d209abf5fc9"),"position._id":mongoose.Types.ObjectId("58d6b7e11e793c9a506ffe8f")},
{$push:{"position.$.applied":{
candidate_id:"test"
}
}
}).exec(function (err, result) {
console.log(result);
res.send({result:result});
});
});
For some reason this wont insert anything for me, the id's are definitely correct also. Anyone know where I'm going wrong?
Return after debug:
Database:
I have a schema:
var Schema = mongoose.Schema;
var TicketSchema = new Schema({
externalId: String,
name: String,
items: [{
externalId: String,
price: Number,
quantity: {
type: Number,
default: 1
},
comment: {
type: String,
default: '',
trim: true
},
entity: {
type: String,
ref: 'Entity'
}
}],
tableId: String
});
mongoose.model('Ticket', TicketSchema);
And I want to populate entity field with an unique field other than ObjectId.
How can I achieve that?
Though late answer. Please check Populate Virtuals for Mongoose 4.5.0
Click the link below
http://mongoosejs.com/docs/populate.html
And scroll down or search for Populate Virtuals you will see it does exactly what you want.
I found Views as one useful approach, though not sure it is the most efficient! For example, in movielens database, I wanted to refer 'movieId' in ratings collection to 'movieId' in the movies collection using 'movieId' as foreign key.
db.createView('rating-movie-view','ratings',[{$lookup:{from:"movies",localField:"movieId",foreignField:"movieId",as:"ratings_movie"}},{ $project:{'userId':1,'movieId':1,'rating':1,'timestamp':1,'ratings_movie.title':1,'ratings_movie.genres':1 } }])
New view "rating-movie-view" thus created has the required fields 'title and 'genres'.
db["rating-movie-view"].findOne()
{
"_id" : ObjectId("598747c28198f78eef1de7a3"),
"userId" : 1,
"movieId" : 1129,
"rating" : 2,
"timestamp" : 1260759185,
"ratings_movie" : [
{
"title" : "Escape from New York (1981)",
"genres" : "Action|Adventure|Sci-Fi|Thriller"
}
]
}
Hope this useful!
Those who are not familiar with movielens data here are the schema
var MovieSchema = new mongoose.Schema({
movieId: Number,
title: String,
genres: String,
});
var RatingSchema = new mongoose.Schema({
userid: Number,
movieId:Number,
rating: Number,
timestamp:Number,
});
//View schema
var RatingViewSchema = new mongoose.Schema({
userid: Number,
movieId:Number,
rating: Number,
timestamp:Number,
rating_movie:{title:String,genres:String}
});
const blogs = this.blogModel
.find(find)
.populate('blogCategory', 'name -_id');
Note -_id will exclude the object _id
I'm not sure if I understood your question correctly.
In Mongoose model, in case we do not specify a primary key, it automatically adds in an extra field called ObjectId and assigns a unique value for each object.
In case we need to specify our own key, we can do it by specifying the key property.
For example:
mongoose.model('Todo', {
todoID: {
type: String,
key: true
},
text: {
type: 'text'
},
done: {
type: Boolean,
default: false,
},
date: {
type: Date,
},
items: [{
entity: {
type: String,
ref: 'Entity'
}
}]
});
I hope, this is what you meant.
If you are asking about fetching objects based on Items -> entity's property,
Todo.find({'items.entity.type':required_type}, function(err, foundTodos){
// ---
});
Thanks,
Use crypto to hash something unique like the objectId , and then save it to your entities.
Var hash = crypto.createHmac('sha256', ticket.objectId).digest('hex');
Ticket.entities= hash;
I was wondering how I can update the array of likes with mongoose:
var postSchema = new mongoose.Schema({
author: String,
content: String,
date: String,
likes: [{theID: String}],
numDate: Number
});
var UserSchema = mongoose.Schema({
username: {
type: String
},
password: {
type: String
},
email: {
type: String
},
first: {
type: String
},
posts: [postSchema],
last: {
type: String
},
followers: [{theID: String}],
following: [{theID: String}],
img: { data: Buffer, contentType: String },
admin: {type: Boolean, default: false}
});
I can push things like new posts to a certain user in the database by
doing this:
User.update({_id: req.user.id}, {
$push: {"posts": {_id : req.body.theData}}
}, function(err, user){
res.redirect('profile');
});
Is there a similar way I can look at a specific user and then a specific post that the user has and update it to push a string to the likes array?
First Of all you need to select the post where you want to update like dislike, you can do it with the help of _id of post {_id: req.user.id,_id:posts._id} then you will need to update like array that can be done this way {$push: {"posts.$.likes": req.user.anotherUserId}} //anotherUserId is of user who liked it. same way you can take a pull of user id if user dislikes the post to remove id from array.
User.update({_id: req.user.id,_id:posts._id}, {
$push: {"posts.$.likes": req.user.id}
}, function(err, user){
});
I have a model in mongoose that looks similar to this:
var TestSchema = new Schema({
test_username: {type: String, required: true},
test_content: {type: String},
reactions: [{
test_username: {type: String, required: true},
value: {type: Number, required: true},
sent_at: {type: Date, required: true, default: Date.now}
}],
created_at: {type: Date, default: Date.now},
updated_at: {type: Date, default: Date.now}
})
it stores my Test object with many reactions in it. Each reaction contains either 1 or -1 value and different usernames.
Now I'm trying to create an endpoint that gets the Test id as an input and returns the total, summed amount from all reactions that it contains.
I started writing it as:
testRoutes.get('/:id/reactions/', functions.validateRequestsGET, function(req, res){
var testId = req.params.id;
var query = Test... //here I'm stuck
query.exec(function(err, reactions){
if(err) {
res.send(err);
return;
}
res.json(reactions);
});
});
can you give me a hint of how to create a query that could return me a json with the summed amount? something like {reactions: 17} or similar?
Try this:
Test.aggregate(
{ $match: {
_id: testId // you might want to convert this from string to ObjectId()
}},
{ $project: {
sumReactions: { $sum: "$reactions.value" }
}}
)
Take a look at group accumulators $group in documentation , good examples too.