2

I want to write a query function which returns an object. The problem is, in my case the function returns undefined.

var filterDataAccordingToDate = function (ref, startTime, endTime) {

    var filteredObj = {};

    ref.orderByChild('date').startAt(startTime).endAt(endTime)
    .once('value', function(snap) {
       filteredObj = snap.val();

       console.log(util.inspect(filterDataAccordingToDate(filteredObj, false, null));
      //Returns the correct object

       return filteredObj;
    });  
}

console.log("DATA RETURNED: " + util.inspect(filterDataAccordingToDate(travelRef, 1466439004, 1466439011), false, null));
// DATA RETURNED: undefined
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Runtime Terror
  • 6,242
  • 11
  • 50
  • 90

3 Answers3

6

As Ami mentions, you can't return a result from an asynchronous call.

What you could do is process your results using a method and simply call your asynchronous call directly without expecting a return result:

var filterDataAccordingToDate = function (ref, startTime, endTime) {
  ref.orderByChild('date').startAt(startTime).endAt(endTime)
    .once('value', function(snap) {
      var filteredObj = snap.val();

      console.log(util.inspect(filterDataAccordingToDate(filteredObj, false, null));
      doSomethingWith(filteredObj);
  });  
}

function doSomethingWith(obj) {
  console.log("DATA RETURNED: " + util.inspect(obj, false, null));
}

filterDataAccordingToDate(travelRef, 1466439004, 1466439011);

I suppose it all depends on what you want to do with your data and how many times you wish to reference it.

Note: I do suggest placing your script in a self-contained function to avoid adding private functions (specific to a single piece of functionality) so that you don't pollute your global namespace. Ben Alman wrote a nice post about Immediately-Invoked Function Expressions (IIFE) or you can make use of a JavaScript namespace.

Edit: As adolfosrs suggests, you can also use promises but keep in mind what browsers you wish to support.

Community
  • 1
  • 1
Clarice Bouwer
  • 3,631
  • 3
  • 32
  • 55
4

I would go with a Promise.

var filterDataAccordingToDate = function (ref, startTime, endTime) {
    var filterDataAccordingToDatePromise = new Promise( function(resolve, reject) {
        ref.orderByChild('date').startAt(startTime).endAt(endTime).once('value', function(snap) {
            filteredObj = snap.val();
            resolve(filteredObj);
        });
    });
    return filterDataAccordingToDatePromise;
};

filterDataAccordingToDate(travelRef, 1466439004, 1466439011).then(function(result){
    //this callback will be trigger when firebase call finish.
    //result is what you set on the resolve.
    console.log("DATA RETURNED: " + util.inspect(result, false, null));
});
adolfosrs
  • 9,286
  • 5
  • 39
  • 67
2

The problem is that Firebase uses an asynchronous listeners to a database reference, hence you can't return from the callback.

You can store the return objects into your dictionary inside the callback.

Ami Hollander
  • 2,435
  • 3
  • 29
  • 47