最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firebase no index defined - Stack Overflow

programmeradmin0浏览0评论

I'm using Firebase to retrieve some data of Users. I need to retrieve only one User with (gameSearching = true).

My data looks like:

Users
|
|_____ John
|        |___ name: John Farmer
|        |___ gameSearching: true
|
|_____ James
|        |___ name: James Smith
|        |___ gameSearching: false
|
|_____ Barbara
         |___ name: Barbara Smith
         |___ gameSearching: true

I'm running this code:

setData(('Users/' + you + '/'), {gameSearching: true});

var ref = new Firebase("");
var child = ref.orderByChild("gameSearching");
child.on("child_added", function (data) {
    var yourself = firebase.getAuth().password.email.split("@", 1)[0];
    data.forEach(
        function (childSnapshot) {
            if (childSnapshot[i].val().gameSearching == true && childSnapshot[i].key() != yourself) {
                var opponent = childSnapshot[i].key();

                setData(('Users/' + opponent + '/'), {gameSearching: false});
                setData(('Users/' + yourself + '/'), {gameSearching: false});
            }
        }
    );


});

Because 'data' has multiple values, I use 'data.forEach' to separate them. After that point I can set a 'return' on 'true' so I only will recieve one User with 'gameSearching: true'.

My firebase rules:

{
  "rules": {
    ".read": true,
    ".write": true,
    ".indexOn": "gameSearching"
  }
}

When I run this code I get the following error:

'Uncaught Error: No index defined for gameSearching'

I have searched for setting a index on 'gameSearching' using '.indexOn' but not with any succes. .html

Does anyone have a example or a solution?


Edit:

I now got the following code:

var ref = new Firebase("");
    ref.orderByChild("gameSearching").equalTo(true).limitToFirst(1).on("child_added", function (data) {
        var yourself = firebase.getAuth().password.email.split("@", 1)[0];

            var opponent = data.key();
            console.log(opponent);

            setData(('Users/' + opponent + '/'), {gameSearching: false});
            setData(('Users/' + yourself + '/'), {gameSearching: false});
            console.log('ja');
    });

I edited my rules of my firebase:

{
"rules": {
    ".read": true,
    ".write": true,
    "Users": {
  ".indexOn": "gameSearching"
}
}

}

The indexOn error wont show anymore, so that's great. But ref.orderByChild("gameSearching").equalTo(true).limitToFirst(1) will runs twice. I don't know how that's possible. I'm using limitToFirst(1)`, so I expect 1 child?

I'm using Firebase to retrieve some data of Users. I need to retrieve only one User with (gameSearching = true).

My data looks like:

Users
|
|_____ John
|        |___ name: John Farmer
|        |___ gameSearching: true
|
|_____ James
|        |___ name: James Smith
|        |___ gameSearching: false
|
|_____ Barbara
         |___ name: Barbara Smith
         |___ gameSearching: true

I'm running this code:

setData(('Users/' + you + '/'), {gameSearching: true});

var ref = new Firebase("https://grootproject.firebaseio.com/Users");
var child = ref.orderByChild("gameSearching");
child.on("child_added", function (data) {
    var yourself = firebase.getAuth().password.email.split("@", 1)[0];
    data.forEach(
        function (childSnapshot) {
            if (childSnapshot[i].val().gameSearching == true && childSnapshot[i].key() != yourself) {
                var opponent = childSnapshot[i].key();

                setData(('Users/' + opponent + '/'), {gameSearching: false});
                setData(('Users/' + yourself + '/'), {gameSearching: false});
            }
        }
    );


});

Because 'data' has multiple values, I use 'data.forEach' to separate them. After that point I can set a 'return' on 'true' so I only will recieve one User with 'gameSearching: true'.

My firebase rules:

{
  "rules": {
    ".read": true,
    ".write": true,
    ".indexOn": "gameSearching"
  }
}

When I run this code I get the following error:

'Uncaught Error: No index defined for gameSearching'

I have searched for setting a index on 'gameSearching' using '.indexOn' but not with any succes. https://www.firebase.com/docs/security/guide/indexing-data.html

Does anyone have a example or a solution?


Edit:

I now got the following code:

var ref = new Firebase("https://grootproject.firebaseio.com/Users");
    ref.orderByChild("gameSearching").equalTo(true).limitToFirst(1).on("child_added", function (data) {
        var yourself = firebase.getAuth().password.email.split("@", 1)[0];

            var opponent = data.key();
            console.log(opponent);

            setData(('Users/' + opponent + '/'), {gameSearching: false});
            setData(('Users/' + yourself + '/'), {gameSearching: false});
            console.log('ja');
    });

I edited my rules of my firebase:

{
"rules": {
    ".read": true,
    ".write": true,
    "Users": {
  ".indexOn": "gameSearching"
}
}

}

The indexOn error wont show anymore, so that's great. But ref.orderByChild("gameSearching").equalTo(true).limitToFirst(1) will runs twice. I don't know how that's possible. I'm using limitToFirst(1)`, so I expect 1 child?

Share Improve this question edited Nov 15, 2015 at 21:13 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Jan 10, 2015 at 15:03 Mr. SamMr. Sam 4051 gold badge6 silver badges21 bronze badges 5
  • What do you mean by "not with any succes"? I've added plenty of indexes and it always works without problem. Can you show the relevant section of your rules? (click the edit link under your question to add the information, do not put it in a comment) – Frank van Puffelen Commented Jan 10, 2015 at 15:19
  • Note that the command is .indexOn, not .indexOf like you've typed above. If you made the same typo in your rules, it will indeed not work. – Frank van Puffelen Commented Jan 10, 2015 at 15:30
  • I mean .indexOn, sorry. The problem I have is that I don't know where to place .indexOn – Mr. Sam Commented Jan 10, 2015 at 15:38
  • Which is why I asked you to add your rules to the question. That also gives you a chance to fix your typo. :-) – Frank van Puffelen Commented Jan 10, 2015 at 15:41
  • Ah ok, I see why your index is not created. I'll write up a second answer for that one, since the problems I highlighted in my initial answer are also relevant. – Frank van Puffelen Commented Jan 10, 2015 at 15:54
Add a comment  | 

2 Answers 2

Reset to default 15

Now that you added your rules, it is clear what is wrong there.

These are your current rules:

{
  "rules": {
    ".read": true,
    ".write": true,
    ".indexOn": "gameSearching"
  }
}

So you allow everyone read and write access on your entire Firebase and tell it to add an index on gameSearching. The problem is that you've defined your index at the top-level, instead of at the level where it needs to be in your Firebase.

This is your current data structure:

{
    "Score" : {
        "sam_lous" : {
            "score" : 2
        }
    },
    "Users" : {
        "hallo" : {
            "gameSearching" : true
        },
        "sam_lous" : {
            "gameSearching" : true
        },
        "test" : {
            "gameSearching" : false
        },
        "test2" : {
            "gameSearching" : true
        }
    }
}

The gameSearching property exists only under children of the Users node. So that is where you should define your .indexOn:

{
  "rules": {
    ".read": true,
    ".write": true,
    "Users": {
      ".indexOn": "gameSearching"
    }
  }
}

With that, your index should be created (in my experience it happens straight away when you save your rules) and the error/warning message should disappear. But to fix the behavior, you should also make the changes that I put in my other answer.

I have to admit that Firebase's documentation on indexing your data, could be clearer on where you define these .indexOn rules. If someone at Firebase is reading along, can you please add some better examples that highlight that .indexOn needs to be defined at the level where the data resides?

Your query orders the data, but fails to filter it. If you change it to this, the query will only match users that are searching for a game:

var query = ref.orderByChild("gameSearching").equalTo(true);

This roughly translates to a SQL of WHERE gameSearching = true, which is what you asked in your previous question. Note that I called the variable query, because it represents a query on the data. Or if you want to stick to SQL metaphors, it is more similar to a VIEW in a relational database.

Since you're listening to child_added your function will be invoked once for each user that fits your query. So the forEach doesn't make any sense to me in your snippet. If you want to use a forEach you can get all users that match the query at once with the value event:

var searchers = ref.orderByChild("gameSearching").equalTo(true);
searchers.on('value', function(searchersSnapshot) {
    searchersSnapshot.forEach(function(snapshot) {
        console.log(snapshot.key());
    });
});

Which will currently log this on your Firebase:

hallo

sam_lous

test2

You can also use child_added to accomplish the same, but in that case you don't need forEach:

var searchers = ref.orderByChild("gameSearching").equalTo(true);
searchers.on('child_added', function(snapshot) {
    console.log(snapshot.key());
});

Fun fact: while on('child_added' triggers the Firebase WARNING of a missing index, on('value' does not. But either way: you should really add the index, because without that performance will suffer unacceptably as you add players.

Since you indicate you only need one child, you can also limit the query further to just give you the first child:

var searchers = ref.orderByChild("gameSearching").equalTo(true).limitToFirst(1);

These and many other operations are covered in sections 2 - 5 of the Firebase Web Guide.

发布评论

评论列表(0)

  1. 暂无评论