My firebase data looks like this:
{
"lambeosaurus": {
"vacationDates" : "2016-12-20 - 2016-12-25",
"length" : 12.5,
"weight": 5000
},
"stegosaurus": {
"vacationDates" : "2016-12-10 - 2016-12-20",
"length" : 9,
"weight" : 2500
}
}
How do i query for all dinosaurs that will be away on vacation on 2016-12-20 (i.e it should return both lambeosaurus and stegosaurus)? Or should I actually store the data differently? If so, how should I store the data for optimum performance? Thanks.
We can filter data in one of three ways: by child key, by key, or by value. A query starts with one of these parameters, and then must be combined with one or more of the following parameters: startAt , endAt , limitToFirst , limitToLast , or equalTo .
A QuerySnapshot contains zero or more DocumentSnapshot objects representing the results of a query. The documents can be accessed as an array via the docs property or enumerated using the forEach method. The number of documents can be determined via the empty and size properties.
You can either go to Firestore Databases > Indexes console and do it, or use the firebase cli. But the easiest option is to just let your code (that performs the query) run and firestore will automatically error out when an index is missing.
Combining the two dates doesn't do much in terms of making the database easier to query.
If you are searching for dinosaurs on holiday on a particular date, they could have gone on holiday anytime before that date. (Unless there is a policy that mandates a maximum number of days in a holiday.) So the end date is probably what you want to query:
{
"lambeosaurus": {
"vacationStart" : "2016-12-20",
"vacationEnd" : "2016-12-25",
"length" : 12.5,
"weight": 5000
},
"stegosaurus": {
"vacationStart" : "2016-12-10",
"vacationEnd" : "2016-12-20",
"length" : 9,
"weight" : 2500
}
}
Any dinosaurs with a vacationEnd
on or after 2016-12-20
will be on holiday on that date if vacationStart
is on or before 2016-12-20
:
function getHolidayingDinosaurs(day) {
return firebase.database()
.ref("dinousaurs")
.orderByChild("vacationEnd")
.startAt(day)
.once("value")
.then((snapshot) => {
let holidaying = [];
snapshot.forEach((child) => {
let val = child.val();
if (val.vacationStart <= day) {
holidaying.push(val);
}
});
return holidaying;
});
}
getHolidayingDinosaurs("2016-12-20").then((holidaying) => console.log(holidaying));
There isn't a straight-forward alternative to performing further filtering on the client, as you can only query Firebase using a single property and the combined dates aren't particularly useful as the start and end could be any dates on or before/after the query date.
Anyway, querying using vacationEnd
is likely to perform most of the filtering on the server - unless you have a lot of dinosaurs that plan their holidays well in advance.
If the above approach results in too much information being retrieved and filtered on the client, you could put in some extra effort and could maintain your own mapping of holidaying dinosaurs by storing some additional data structured like this:
"holidays": {
...
"2016-12-19": {
"stegosaurus": true
},
"2016-12-20": {
"lambeosaurus": true,
"stegosaurus": true
},
"2016-12-21": {
"lambeosaurus": true
},
...
}
Firebase's multi-location updates can be used to make maintaining the mapping a little easier (there are more multi-location examples in this answer):
firebase.database().ref().update.({
"dinosaurs/lambeosaurus": {
"vacationStart" : "2016-12-20",
"vacationEnd" : "2016-12-25",
"length" : 12.5,
"weight": 5000
},
"holidays/2016-12-20/lambeosaurus": true,
"holidays/2016-12-21/lambeosaurus": true,
"holidays/2016-12-22/lambeosaurus": true,
"holidays/2016-12-23/lambeosaurus": true,
"holidays/2016-12-24/lambeosaurus": true,
"holidays/2016-12-25/lambeosaurus": true
});
A query on holidays/2016-12-20
would then return an object with keys for each holidaying dinosaur.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With