Using equalTo() function in Firebase Database JavaScript v9 - javascript

I am trying to use the equalTo function in the Firebase Database JavaScript v9 SDK. It's not very well documented like V8 is so can't figure out how to do what I want to do.
I want to filter results by the type field. My parent field is request-log with child elements like below.
{"backtrace":false,"message":false,"organisationID":"Empty","postData":false,"referrer":"Empty","remoteIP":"0.0.0.0","requestMethod":"POST","time":1630129562,"type":"Error","url":"Empty","user":{"email":"Empty","firstName":"George","id":37,"lastName":"Bates"},"userAgent":"Empty"}
I am trying the following, but not getting any results when loaded:
const readNewLogEntries = query(child(ref(db), 'request-log'), equalTo('Error', 'type'));
I have also tried this, as the reference docs say for the 2nd argument in the equalTo() function
This argument is only allowed if ordering by child, value, or priority.
But this isn't working either
const readNewLogEntries = query(child(ref(db), 'request-log'), orderByChild('type'), equalTo('Request', 'type'));
EDIT: Screenshot of DB

Remove the second parameter from equalTo().
The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have exactly the specified key as their key name. This can be used to filter result sets with many matches for the same value.
const getData = async () => {
const readNewLogEntries = await get(
query(ref(db, "request-log"), orderByChild("type"), equalTo("Request"))
// Filters where "type" is equal to "Request". Single arg here ⬆
);
console.log(readNewLogEntries.val())
return readNewLogEntries.val();
};
You can read more about the parameters in the documentation

Related

How to output the firebase snapshot in reverse order?

I am trying to get the latest 3 data from the database and display them in reverse order in the HTML page.
Code:
var refForevent = database.ref('/events/post');
refForevent.orderByChild("intro").limitToLast(3).on('child_added', function(snapshot){
var eventlist = []
eventlist.push(snapshot)
console.log(eventlist)
eventlist.reverse()
document.getElementById("event1date").innerHTML = moment(eventlist[0].intro).format("MMM Do YYYY");
document.getElementById("event1title").innerHTML = eventlist[0].title;
document.getElementById("event2date").innerHTML = moment(eventlist[1].intro).format("MMM Do YYYY");
document.getElementById("event2title").innerHTML = eventlist[1].title;
document.getElementById("event3date").innerHTML = moment(eventlist[1].intro).format("MMM Do YYYY");
document.getElementById("event3title").innerHTML = eventlist[1].title;
})
Output: Output that I am getting
Database:
I see that the field intro contains a date.
Here is one solution:
Take the value of this field
Remove the hyphen separators (e.g. from 2020-12-10 you get the number 20201210)
Multiply this number by -1
Store the resulting value in another field
Sort on this field
Alternatively (and more elegant...), use the date to create a Timestamp, multiply it by -1 and use it as explained above, i.e. store the resulting value in another field and sort on this field.
Since you're listening to the child_added event, your function gets called with each post node that matches the query in the order in which Firebase returns them. So your eventlist will only ever contain one node at a time.
To reverse the items, you can either get Firebase to return the values in reverse order, as Renaud suggest (I'll also link some answers below), or you can listen to all results in once go and then reversing client-side (as your code already seem to be trying). The latter would look something like:
var refForevent = database.ref('/events/post');
refForevent.orderByChild("date").limitToLast(3).on('value', function(results){
var eventlist = []
results.forEach(function(snapshot) {
eventlist.push(snapshot.val())
});
eventlist.reverse()
console.log(eventlist);
...
})
So this:
Listens to the value event, instead of child_added, so that it gets all matching child nodes in one go.
If then loops over the results, adding them to the array,
It calls .val() on each child snapshot, to get the value from it.
For more on descending sorting, also see:
Display posts in descending posted order (the oldest I could find describing the trick with negative values)
firebase -> date order reverse (with many more links from there)
Sorting in descending order in Firebase database

Trouble calling specific field in Firebase based on the paramater in the URL

I am trying to call the relevent data from Firebase based on the paramater in the URL.
For example:
var userId = 'EqBOy1RVZacBCaNlzbG9NDHrXl23'
//sets the variable to the exercise name in the url
var exerciseName = this.$route.params.exercise_name //'dumbbell_extension'for example
db.collection('track').doc(userId).get().then((doc) => {
if (doc.exists) {
this.exerciseData = doc.data().exerciseName //Returns 'undefined'
}
})
Here is a picture of the database:
Firebase Document Image
This returns undefined despite of the data existing in Firebase and everything else working as intended. I presume this is because it is actually searching for a field called exerciseName instead of the variable exerciseName.
The data() method of a DocumentSnapshot "retrieves all fields in the document as an Object".
You should therefore use the square bracket notation, which allows you to access the Object properties by name, as follows:
var userId = 'EqBOy1RVZacBCaNlzbG9NDHrXl23'
//sets the variable to the exercise name in the url
var exerciseName = this.$route.params.exercise_name //'dumbbell_extension'for example
db.collection('track').doc(userId).get().then((doc) => {
if (doc.exists) {
this.exerciseData = doc.data()[exerciseName]
}
})
You may also be interested by this answer https://stackoverflow.com/a/4968460/7015400, which gives more details about the square bracket notation.
Your code is looking for a field called "exerciseName" in the document, but the document has no such field. The only field in your document, as shown in the screenshot, is called "dumbbell_extension", and we can't see what it contains (it could be a list or map).
Since we don't know what your code is expecting to do, there's no much else to be said. Your code needs to use the names of the fields that are present in the document, or check to see if they actually exist before using them.

Create array type of push in firebase

I'm attempting to create this structure in firebase:
inMinistries
--uidOfGroup1
----0: uidOfGroup1Member
----1: uidOfGroup1Member
----2: uidOfGroup1Member
--uidOfGroup2
----0: uidOfGroup2Member
----1: uidOfGroup2Member
In the above example inMinistries is the first node, then we have uidofGroup1 which would be a uid of a Group then I want child nodes to appear like uidOfGroup1Member. There are several so I can't say exactly how many I need.
Here is my attempt to create the above:
class Firebase {
constructor() {
app.initializeApp(firebaseConfig);
this.auth = app.auth();
this.db = app.database();
this.storage = app.storage();
}
This is how I set the uidOfGroups
this.db.ref(`inMinistries/${uidOfGroup}`).set('members')
I pass a uid value I receive from another call. I set 'members' so that I could replace it with a group of members later.
I then try to create uidOfGroup1Members, uidOfGroup2Members. I get stuck on this part. If I do a set like so:
this.db.ref(`/inMinistries/${uidOfGroup}}`).set(memberId);
I can only pass the memberId once, meaning I'd need to have the full list of uidOfGroupMembers which I don't have all at once. I'd like to be able to push it like I would in an array. But if I do push:
this.db.ref(`/inMinistries/${uidOfGroup}}`).push(memberId);
then it adds an extra uid to the value before like so:
Note the above is actually using the uids. How can I achieve the original desired result I placed on top?
If you have no constraint on how you save the different uidsOfGroupMember under a specific uidOfGroup (in particular no need for using a specific "index" (i.e. 0, 1, 2)), you could use the set() method as follows:
var uidOfGroup = 'uidOfGroup1';
var uidOfGroup1Member = 'uidOfGroup1Member'; //Of course, here you can assign the value you want, e.g. -Lwk98a...
this.db.ref(`/inMinistries/${uidOfGroup}/${uidOfGroup1Member}`).set(
uidOfGroup1Member
);
var uidOfGroup2Member = 'uidOfGroup2Member';
this.db.ref(`/inMinistries/${uidOfGroup}/${uidOfGroup2Member}`).set(
uidOfGroup2Member
);
One difference between the push() and the set() methods is that push() creates a child location with an auto generated unique key, which is the cause of your problem.

Can't return correct reference from db.ref('reference').orderByChild('child').equalTo('value').ref;

I'm trying to grab the reference of a query result, however all I'm getting a reference to is the original key. For example;
const reference = db.ref('reference').orderByChild('child').equalTo('value').ref;
My reference variable seems to be pointing towards the node 'reference' and not the result of my query. Is this correct behaviour as the documents only mention that equalTo returns a reference, which I've assumed is to the result of the query?
Is there any alternative way of grabbing a reference to a query result?
The .ref at the end of your query returns the original reference on which you're running the query. So these two lines have the exact same result:
const reference = db.ref('reference').orderByChild('child').equalTo('value').ref;
const reference = db.ref('reference');
To keep the actual query, use:
const reference = db.ref('reference').orderByChild('child').equalTo('value');

iteration of a JSON containg objects

I am trying to write a function that takes pokemon’s name as an argument and find out which all pokemon have that name in their “next_evolution” field
Consider the following JSON dataset -
visit https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json
now for that, I've written the following function:
var infoOfPokemon = function(nameOfPokemon,allPokemon){
for(x in allPokemon){
if(allPokemon[x].next_evolution.includes(nameOfPokemon)){
console.log('pokemons found: '+allPokemon[x].name)
} else{
null
}
}
}
var nameOfPokemon =prompt('enter the name of Pokemon')
infoOfPokemon(nameOfPokemon,pokemonData.pokemon)
but it is returning an error which says
Uncaught TypeError: Cannot read property 'includes' nextEvolution.js:4090 of undefined
One or more of your pokemon does not have a 'next_evolution' field set (for example, the one with id 3 in your file). Hence allPokemon[x].next_evolution evaluates to undefined and you cannot read 'includes' on that.
Check for the existence of next_evolution, first.
if (allPokemon[x].next_evolution &&
allPokemon[x].next_evolution.includes(nameOfPokemon)) { ...
and find out which all pokemon have that name in their “next_evolution” field
That should make you think of filter. You want to filter the list of pokemon to find the matching ones.
But, as already pointed out, you need to be able to return false in your filter predicate if the pokemon you're testing does not have a next_evolution field. You can do that via testing, as suggested in another answer: pokemon.next_evolution && pokemon.next_evolution.includes..., or you can default it, as below: (pokemon.next_evolution || []).includes...
(Note though that both you original and that answer miss a step, which is to then collect that name properties from those next_evolution values.
So here is a simple function which should filter the list to find the correct items. To use it with a call to your API, I wrap it in a fetch call, and simply console.log the results. Obviously, you might well have other ways to call it.
const infoOfPokemon = (name, all) => all.filter(pokemon =>
(pokemon.next_evolution || []).map(p => p.name).includes(name)
)
fetch('https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json')
.then(resp => resp.json())
.then(allPokemon => console.log(
infoOfPokemon('Butterfree', allPokemon.pokemon) //~> [{Caterpie}, {Metpod}]
))
You cannot use includes function directly on array having objects instead of single object. It will give false as output.
For e.g:
var pets = [{'name':'cat'},{'name':'dog'},{'name':'bat'}];
console.log(pets.includes("cat")) //false
This results in false always.
Proper way is to use a map to get a particular object field on which you want to use includes function.
e.g:
var pets = [{'name':'cat'},{'name':'dog'},{'name':'bat'}];
console.log(pets.map((obj)=> obj.name).includes("cat")); //true
In Your case first see if allPokemon[x].next_evolution is undefined or not (i.e next_evolution key is present or not)
code becomes:
if (allPokemon[x].next_evolution &&
allPokemon[x].next_evolution.(obj)=> obj.name).includes(nameOfPokemon)) { ...

Categories

Resources