user3240644
user3240644

Reputation: 2281

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.

Upvotes: 9

Views: 13463

Answers (2)

cartant
cartant

Reputation: 58400

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.

Upvotes: 14

Ros&#225;rio P. Fernandes
Ros&#225;rio P. Fernandes

Reputation: 11326

I recommend storing the data in a different way. Use one attribute for "vacationStart" and one for "vacationEnd". And also, put all the dinosaurs inside a "dinousaurs" node, and not in the root node.

So in order to query for all dinosaurs that will be away on vacation on 2016-12-20, you would use the query:

var query = firebase.database().ref('dinousaurs').orderByChild('vacationStart').equalTo('2016-12-20');

Upvotes: 0

Related Questions