In Firebase's realtime Database, does `equalTo(arg)` only work if arg is an object?

Viewed 351

db1:

a: {
  b: {
    c: "d"
  }
}

db2:

a: {
  b: "c"
}

db.ref(`a/b`).orderByKey().equalTo('c').on('value', (e) => {
  console.log(e.val()); 
})

When referencing db1, e.val() returns {c: "d"}.

When referencing db2, e.val() returns null. Why is this?


Some more experiments:

db.ref(`a/b`).orderByKey().on('value', (e) => { 
  console.log(e.val()); 
})

When referencing db1 & db2, returns {b: "c"} & "c" respectively.


From this, I can only guess that, for some reason, equalTo(arg) doesn't like to deal with args that do not object.

1 Answers

To begin my explanation, I'd say it is not right that equalTo(arg) works only if arg is an obj. No rule about arg's type. Just arg's type will be used during running query but this doesn't mean arg should be an object. arg can be any kind of values like string, char, date, int but not sure it can be an array.

Let me give you some tips on how the above equalTo works in your code. First, in firebase, we implement query by combining sorting(order-by method) and filtering(limit-range method) against the path. In normal way, we use query in this way:

db.ref(path).sorting function.filtering function.on('value',snapshot=>{});

In your code, orderByKey() is sorting function and equalTo('c') is filtering function applying on result of sorted. equalTo() will be processed after complete of orderByKey() which returns sorted array. Important thing is that e.val() of equalTo('c') is also returning JSON object which consists of more than 1 matching obj, not a single result because there will be over 1 result that match to 'c'. That's the reason why you can see result {c:"d"} after running equalTo on db1.

Let's assume you have two obj which has the same key: c under b

a: {
  b: {
    c: "d",
    c: "e",
  }
}

Without orderByKey, equalTo('c') will run over all objects under b. Then result of running equalTo('c'): e.val() will be {c:"d",c:"e"} But if you run orderByKey before equalTo('c') then equalTo('c') runs on sorted array : {c: "d"} but result is still kind of object array not a single value : {c: "d"}.

So point is equalTo('key') returns object array kind of this style: {key:"value1",key:"value2",...} If no result then returns null. In my experience, if I want to get the value of running query equalTo(), I use orderByKey() before equalTo and return the first element of the result. So this works for you.

 db.ref(`a/b`).orderByKey().equalTo('c').on('value', (snapshot) => {
  // important; snapshot.val() will be json object which contains more than 1 matched objs  not a single key-value object.
  const result = snapshot.val(); 
  const value = Object.values(result)[0];
  console.log("value",value);
})

// db2 also works the same. just it has deep 1 less than db1. but the same.
Related