Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase query for data within a date range

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.

like image 576
user3240644 Avatar asked Dec 29 '16 14:12

user3240644


People also ask

How do you filter data in firebase realtime database?

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 .

What is QuerySnapshot in firebase?

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.

How do I query Subcollection in firestore?

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.


1 Answers

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.

like image 93
cartant Avatar answered Oct 18 '22 21:10

cartant