У меня есть коллекция availabilities
. Внутри этой коллекции может быть несколько записей, основанных, например, на дате:
{
"_id": "64b03ed794d87927a3066e13",
"startDateTime": "2023-07-07T18:00:00.000Z",
"endDateTime": "2023-07-12T15:00:00.000Z",
"availabilityType": "blackout"
}
{
"_id": "64b03eb094d87927a3066ddb",
"startDateTime": "2023-07-03T18:00:00.000Z",
"endDateTime": "2023-07-06T15:00:00.000Z",
"availabilityType": "blackout"
}
Я пытаюсь найти лучший способ создать массив дат для месяца, и если есть «доступность» для некоторых дней, то вернуть это в массиве дат. Я думал о создании массива дней с помощью javascript, но тогда мне пришлось бы повторять каждый день, чтобы увидеть, есть ли какие-либо availabilities
в этот день; это кажется очень неэффективным.
В идеале то, что я хочу построить, похоже на следующее:
[
{
"date": "2023-07-01",
"availabilityType": "available"
},
{
"date": "2023-07-02",
"availabilityType": "available"
},
{
"date": "2023-07-03",
"availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
},
{
"date": "2023-07-04",
"availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
},
{
"date": "2023-07-05",
"availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
},
{
"date": "2023-07-06",
"availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
},
... etc up to July 31
]
Любые предложения о том, как это можно сделать?
🤔 А знаете ли вы, что...
JavaScript поддерживает работу с графикой и аудио, что позволяет создавать мультимедийные веб-приложения.
Один из подходов заключается в предварительном создании массива для месяца со статусом по умолчанию "available"
для всех дней, а затем циклическим просмотром доступности и обновлением соответствующих записей в вашем массиве. например, сначала сгенерируйте массив за месяц:
const getMonth = (year, month) => {
const start = new Date(year, month, 1);
const end = new Date(year, month + 1, 1);
const days = [];
for(let day = start; day < end; day.setDate(day.getDate() + 1)) {
days.push({
date: day.toISOString().slice(0, 10),
availabilityType: 'available',
});
}
return days;
};
const monthData = getMonth(2023, 6); // for July 2023 (month is 0-indexed)
Затем обновите данные о доступности данными массива:
const availabilities = [
{ startDateTime: "2023-07-07T18:00:00.000Z", endDateTime: "2023-07-12T15:00:00.000Z", availabilityType: "blackout" },
{ startDateTime: "2023-07-03T18:00:00.000Z", endDateTime: "2023-07-06T15:00:00.000Z", availabilityType: "blackout" }
];
for (let av of availabilities) {
const startDay = new Date(av.startDateTime).getDate();
const endDay = new Date(av.endDateTime).getDate();
for (let i = startDay - 1; i < endDay; i++) {
monthData[i].availabilityType = av.availabilityType;
}
}
Это предполагает, что availabilities
отсортировано в порядке возрастания и не содержит перекрывающихся интервалов. Если эти предположения неверны, вам может потребоваться сначала отсортировать availabilities
и добавить дополнительные проверки во втором цикле.
Вот еще один взгляд на это:
const bookings=[{ "_id": "64b03ed794d87927a3066e13", "startDateTime": "2023-07-07T18:00:00.000Z",
"endDateTime": "2023-07-12T15:00:00.000Z", "availabilityType": "blackout"},
{"_id": "64b03eb094d87927a3066ddb", "startDateTime": "2023-07-03T18:00:00.000Z",
"endDateTime": "2023-07-06T15:00:00.000Z", "availabilityType": "blackout" }];
const monthCal = {}; // set up the calendar for one month: July 2023
for (let d=1, m=6, y=2023, ld=new Date(y,m+1,0).getDate(); // set to 00:00h the following day
d <= ld; d++ ) monthCal[`${y}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`]=false;
bookings.forEach(b=>{
// define the cut-off date ld as "00:00h", the day after endDateTime:
const ld=new Date(b.endDateTime); ld.setDate(ld.getDate()+1); ld.setHours(0);
for (let d=new Date(b.startDateTime); d < ld; d.setDate(d.getDate()+1))
monthCal[d.toISOString().slice(0,10)]=true;
});
console.info(monthCal)
// or if you want the original output format:
console.info(Object.entries(monthCal).map(([date,v])=>({date,availabilityType:v?"booked":"available"})));
Поскольку объект monthCal
позволяет находить даты напрямую, без использования внутреннего цикла, это может быть немного более эффективным, чем сканирование массива объектов.
Вы можете просто добиться этого, определив startDate
и endDate
для представления диапазона дат месяца, для которого вы хотите получить подробности. В демонстрационных целях я использую диапазон месяцев июля.
const startDate = new Date("2023-07-01");
const endDate = new Date("2023-07-31");
Затем мы будем перебирать каждую дату, используя цикл for, начиная с startDate
и увеличивая на один день до endDate
.
В цикле мы проверяем, попадает ли текущая дата в диапазон startDateTime
и endDateTime
любого объекта в массиве с типом доступности blackout
. Если это так, переменная isBooked
устанавливается на true
, указывая, что дата забронирована. В противном случае isBooked
остается false
, указывая на то, что дата свободна.
Наконец, мы помещаем объект в массив allDates
для каждой даты, устанавливая свойство даты в отформатированную строку даты, а доступное свойство — либо в booked
, либо в available
в зависимости от значения isBooked.
Живая демонстрация:
const array = [
{
"_id": "64b03ed794d87927a3066e13",
"startDateTime": "2023-07-07T18:00:00.000Z",
"endDateTime": "2023-07-12T15:00:00.000Z",
"availabilityType": "blackout"
},
{
"_id": "64b03eb094d87927a3066ddb",
"startDateTime": "2023-07-03T18:00:00.000Z",
"endDateTime": "2023-07-06T15:00:00.000Z",
"availabilityType": "blackout"
}
];
const startDate = new Date("2023-07-01");
const endDate = new Date("2023-07-31");
const allDates = [];
for (let date = startDate; date <= endDate; date.setDate(date.getDate() + 1)) {
const dateString = date.toISOString().split('T')[0];
const isBooked = array.some(item => {
const startDateTime = new Date(item.startDateTime);
const endDateTime = new Date(item.endDateTime);
return dateString >= startDateTime.toISOString().split('T')[0] && dateString <= endDateTime.toISOString().split('T')[0] && item.availabilityType === "blackout";
});
allDates.push({ date: dateString, available: isBooked ? "booked" : "available" });
}
console.info(allDates);