2

I have a firebase reference like this:

$scope.lessons = $firebaseArray(firebase.child('Lessons').orderByChild('courseID').equalTo($state.params.courseID));

I'm outputting the lessons like this:

<ul>
        <li class="lesson" ng-if="lesson.moduleID == module.$id" ng-repeat="lesson in lessons" lessonid="{{lesson.$id}}">
            <lessonedit></lessonedit>
        </li>
</ul>

I need to order the lessons by priority, but when I add the orderByPriority() function to the end of the firebase reference it says I can only use one orderBy call.

I tried the filter lesson in lessons | orderByPriority but it says that filter does not exist?

Jordash
  • 2,926
  • 8
  • 38
  • 77

3 Answers3

2

Currently, you can't mix .orderByPriority() and .orderByChild() as they are different order by functions.

However, you can still solve your problem by only using .orderByPriority(), if you re-structure your data.

Structuring your data a specific way allows you query your data, as if you could use two orderBy functions.

In your case you have a location of "Lessons" that all have a push-id key of their "lesson id": /lessons/$lessonID.

You could change your structure to key off of the courseId and then the lesson_id: /lessions/$courseID/$lessonID.

The data would look like this:

{
  "lessons": {
    "1": {
      "-K4NQTsjo3iswX4PhKUw": {
        title: "My Course"
      },
      "-K4NAWsjo5iswX4Jk4fa": {
        title: "Another Course"
      }
    }
    "2": {
      "-K4NQTsjo3iswX4PhKUw": {
        title: "My Course"
      },
      "-K4NQPjMZVCoFRYc_1v5": {
        title: "Intro to Data Structure"
      }
    }
  }
}

Now since the key uses the courseID, we can order by by both courseID and priority:

var courseID = $state.params.courseID;
var ref = new Firebase('<my-firebase-app>.firebaseio.com/lessons');
var query = ref.child(courseID).orderByPriority();
var syncArray = $firebaseArray(query);

You can store this in a factory in your AngularJS code.

angular.module('app', ['firebase')
  .constant('FirebaseUrl', '<my-firebase-app>')
  .service('RootRef', ['FirebaseUrl', Firebase])
  .factory('Lessons', Lessons)
  .controller('MainCtrl', MainCtrl);

function Lessons(RootRef) {
  return function Lessons(courseID) {
    var ref = RootRef.child('Lessons');
    var query = ref.child(courseID).orderByPriority();
    return $firebaseArray(query);
  }
}

function MainCtrl($scope, $state, Lessons) {
  var courseID = $state.params.courseID;
  $scope.lessons = Lessons(courseID);
}
Community
  • 1
  • 1
David East
  • 31,526
  • 6
  • 67
  • 82
  • Is there a way to create lessons with a sequential ID like this? – Jordash Nov 30 '15 at 15:56
  • Not natively with Firebase. Sequential/index based IDs are a poor fit with realtime data. When the ID is just a number it can easily collide when indexes change. Push IDs are unique which helps avoid any collisions and or race conditions. – David East Nov 30 '15 at 16:06
  • Then i'm stuck using push id's and I can't change the structure. I added a new field called `priority` to the item and I can orderBy that, it's too bad because I can't use any of Firebases built in set priority or orderby priority methods, but it works this way without too much hassle. – Jordash Nov 30 '15 at 17:00
  • You can always migrate to push-ids by updating the sequential ids. If my answer works please mark it as accepted to keep the unanswered queue clean. – David East Nov 30 '15 at 17:11
1

If Priority is an attribute of lesson, you can use the angular filter orderBy like this:

<ul>
    <li class="lesson" 
        ng-if="lesson.moduleID == module.$id" 
        ng-repeat="lesson in lessons | orderBy:'Priority'" 
        lessonid="{{lesson.$id}}">
        <lessonedit></lessonedit>
    </li>
</ul>
Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122
  • It's not an attribute unfortunately, priority is built into Firebase, they have functions to update the priority, but in this case it's of no use because you can't order by it. – Jordash Nov 30 '15 at 07:57
  • I eventually had to add a priority attribute in order to get this to work. – Jordash Nov 30 '15 at 17:01
  • 1
    How much data are you pulling down with this? If it's a small amount then this is a fine solution. But this won't scale with larger data sets. – David East Nov 30 '15 at 17:24
0

Using Firebase's new Query API, you can do this with:

var ref = new Firebase('https://your.firebaseio.com/');

ref
  .orderBy('genre')
  .startAt('comedy').endAt('comedy')
  .orderBy('lead')
  .startAt('Jack Nicholson').endAt('Jack Nicholson')
  .on('value', function(snapshot) { 
  console.log(snapshot.val()); 
  });

Note that the new Query API is still in beta, so things may change before it's officially released.

See this jsbin for a similar query on Firebase's sample data set.

You can check the original Post of Frank van Puffelen here

Community
  • 1
  • 1
souravlahoti
  • 716
  • 2
  • 8
  • 29
  • Firebase queries are not in beta, they have been available since 11-04-14. https://www.firebase.com/blog/2014-11-04-firebase-realtime-queries.html – David East Nov 30 '15 at 12:39