Skip to content

Instantly share code, notes, and snippets.

@Agoreddah
Created August 3, 2017 08:54
Show Gist options
  • Save Agoreddah/cb65b72e6c7a35691b4a5dc179ec2759 to your computer and use it in GitHub Desktop.
Save Agoreddah/cb65b72e6c7a35691b4a5dc179ec2759 to your computer and use it in GitHub Desktop.
Calculate price with mongo aggregate query - Evaluate array of dates with array of prices
// Simple document example
// Every boat contains array of prices for different days
// We decided to use simple concatenated date int to evaluate date ranges, f.e. date '2017-08-24' becomes integer 20170824
// If user wants to reservate boat in dates when prices is not defined, it will not be shown in results
Boat = {
_id : ObjectId("100000000000000000000001"),
prices : [
// price available for august
{
price : NumberInt(100),
check_in : NumberInt(20170801),
check_out : NumberInt(20170831)
},
// price available for september
{
price : NumberInt(50),
check_in : NumberInt(20170901),
check_out : NumberInt(20170930)
}
]
}
// period:
// -- we used to generate price for every day differently
// -- dates array is generated automatically from user's checkIn and checkOut dates
// -- dates array contains minimum 1 day, and maximum 28 days
// -- last date of reservation is not calculated - user returns boat and it's available for another user
// example: user wants to rent a yacht for 1 week in august, from 12. to 19.
var period = [20170812,20170813,20170814,20170815,20170816,20170817,20170818];
db.boats.aggregate([
{
$project : {
data : {
_id : '$_id',
dates : period,
prices : {
$map : {
input : period,
as : 'date',
in : {
// $filter returns array, we need to get data from it's index 0
$arrayElemAt : [{
$filter : {
input : '$prices',
as : 'price',
cond : {
$and : [
{ $gte : ['$$date', '$$price.check_in']},
{ $lte : ['$$date', '$$price.check_out']}
]
}
}
}, 0]
}
}
}
}
}
},
{
$match : {
// if boat doesn't have prices set for user's checkIn & checkOut dates, $filter returns null
'data.prices' : { $ne : null }
}
},
{
// group the results
$group : {
_id : '$data._id',
prices : { $first : '$data.prices' }
}
},
{
// $prices contains array of objects, we would like to return only price integers
$unwind : '$prices'
},
{
// now $prices is an array of integers (prices) per day
// totalPrice is sum of all $prices
$group : {
_id : '$_id',
prices : { $push : '$prices.price' },
totalPrice : { $sum : '$prices.price' }
}
}
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment