Firebase Database: why do the key/ref in my queried datasnapshot refer to its parent? - javascript

I would like to delete an entry from the realtime database that i looked up through a query but i am getting unexpected results for both the ref and key properties.
ref('photos/users/USERID')
.orderByChild('photoname')
.equalTo('photoname i want to look up')
.limitToFirst(1)
.query('once')
.then(snapshot => {
// correct data at 'photos/users/USERID/PHOTOID'
const entry = snapshot.val();
// seems to be the ref to photos/users/USERID'
const ref = snapshot.ref;
// seems to be USERID
const key = snapshot.key
})
Why aren't these the ref/key to the entry i just found? And what is the best approach to remove this entry?

When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
Your code needs to take this list into account, and iterate over snapshot.forEach() to get the actual matching item:
ref('photos/users/USERID')
.orderByChild('photoname')
.equalTo('photoname i want to look up')
.limitToFirst(1)
.query('once')
.then(snapshot => {
snapshot.forEach(child => {
const entry = child.val();
const ref = child.ref;
const key = child.key
});
})

Your ref and key are based on ref('photos/users/USERID'), not the filtered subset you have created. Is there any reason you wouldn't call ref('photos/users/USERID/PHOTOID')?

Related

How to query for objects with a certain property in a Firestore collection, Firebase

I am trying to query for objects in firestore collection with a certain property, my Firestore DB looks as shown in the below picture.
The below code does not work as I am interested in querying for objects based on the the property inside an object. In this case I want all the cases (objects) with "status"=="treated" Is there a way to do it ?
const db = firebase.firestore();
const casesRef = db.collection("mgm/hospital/cases");
// Create a query against the collection.
var query = casesRef.where("status", "==", "active").limit(25);
const queryRef = query.get();
queryRef.then(function(documentSnapshots) {
const cases = documentSnapshots.docs.map((doc) => doc.data());
console.log(cases);
});
Since the field patientDetails is a map, the following should do the trick:
var query = casesRef.where("patientDetails.status", "==", "active").limit(25);

Delete a array element from a Firestore database

I'm trying to delete an element from an array in a Firestore document. However, none of the approaches I tried had worked so far. My last attempt was like this:
const ref = firestore().collection('events').doc(extraid);
ref.get().then(document => {
const thing = document.data();
const rejected = thing.rejected || [];
const interested = thing.interested || [];
const fieldIndex = interested.findIndex(obj => obj.interestedId === sender);
const fieldToDelete = interested[fieldIndex];
firebase.firestore.FieldValue(fieldToDelete);
firebase.firestore.FieldValue.delete(fieldToDelete);
});
How can I delete an element from an array in a Firestore document?
You will have to update() the modified array field back to the document as suggested by the documentation. Calling FieldValue.delete() isn't enough - that just creates a FieldValue token that you can pass to update() to make the change. It will look something like this:
ref.update('interested', FieldValue.delete(fieldToDelete))

how to get items from array on respectively

I have an array contain unique keys, these keys I want to take it to get his Data from firebase real-time DB
the array like this
["dtnMG3dVEQXL1TPct3awl927jax2", "y5eAQppoEZRELsDL3hLbY5b0A763"]
so I iterate it using forEach Method to get a single key to check if found in the users tree or not But the result is null?
But when I Log the keys.forEach(key => console.log(key)) I can Get every key in a single line
firebase
.database()
.ref("users")
.child(keys.forEach(key => key))
.once("value")
.then(users => {
// let username = users.val().username;
console.log(users.val());
// Object.assign(users, { [Object.keys(users)]: username });
});
Edit
So thats fine and get every single username, Now the new issues is i want to save these names to other object i have
users = {
dtnMG3dVEQXL1TPct3awl927jax2: // the unique key
-LmUSeyWtBPqcoN8l6fd: [{…}]
-LmUgcbdzElxWpLkN-F9: [{…}]
// here's i want to add somthing like thies
-username : "userOne" //I got it from the Looping
y5eAQppoEZRELsDL3hLbY5b0A763:
-LmSTYlxa7bjy0Beazmy: [{…}]
-LmUad3lvkPdTQDFo4Ds: [{…}]
-LmUyDmGcEmYKOJnvEiA: [{…}]
// here's i want to add somthing like thies
-username : "userTwo" // I got it from the Looping
}
keys.forEach(key => key)
This return every element of the array keys. And you are passing these elements to the child function. However, child functions expects only one argument.
Try this:
for( let key of keys){
firebase
.database()
.ref("users")
.child(key)
.once("value")
.then(users => {
// let username = users.val().username;
console.log(users.val());
// Object.assign(users, { [Object.keys(users)]: username });
});
}
Side not: Do not call async function inside forEach loop.
.child(keys.forEach(key => key)) - This is your problem. This forEach effectively returns all your array values one by one. But you call it inside a function with one argument that gets called one time. So it will only check for the first value in your array and the rest will be dumped, so its like looking inside a 1-element array.
Solution is to perform the DB calls inside the iteration:
keys.forEach( key => {
firebase
.database()
.ref("users")
.child(key)
.once("value")
.then(users => {
// let username = users.val().username;
console.log(users.val());
// Object.assign(users, { [Object.keys(users)]: username });
}});
EDIT:
to do what you wanted after you edited, assuming the variable curUser holds the username you want to insert and curKey is the key associated to that username, just: users[key]["username"] = curUser;. This will reference the property which is named after curKey in the users object, and will create a "username" property in it and store the value there.
Notice that if you already have "username" property in this key object it will be overriden.
** I assumed the data structure of the key-properties inside "users" are objects even tho your code doen't really show it.

Can I treat items found through a Promise.all as a firebase collection?

I am stuck in what I thought was a very simple use case: I have a list of client ids in an array. All I want to do is fetch all those clients and "watch" them (using the .onSnapshot).
To fetch the client objects, it is nice and simple, I simply go through the array and get each client by their id. The code looks something like this:
const accessibleClients = ['client1', 'client2', 'client3']
const clients = await Promise.all(
accessibleClients.map(async clientId => {
return db
.collection('clients')
.doc(clientId)
.get()
})
)
If I just needed the list of clients, it would be fine, but I need to perform the .onSnapshot on it to see changes of the clients I am displaying. Is this possible to do? How can I get around this issue?
I am working with AngularFire so it is a bit different. But i also had the problem that i need to listen to unrelated documents which can not be queried.
I solved this with an object which contains all the snapshot listeners. This allows you to unsubscribe from individual client snapshots or from all snapshot if you do not need it anymore.
const accessibleClients = ['client1', 'client2', 'client3'];
const clientSnapshotObject = {};
const clientDataArray = [];
accessibleClients.forEach(clientId => {
clientSnapshotArray[clientId] = {
db.collection('clients').doc(clientId).onSnapshot(doc => {
const client = clientDataArray.find(client => doc.id === client.clientId);
if (client) {
const index = clientDataArray.findIndex(client => doc.id === client.clientId);
clientDataArray.splice(index, 1 , doc.data())
} else {
clientDataArray.push(doc.data());
}
})
};
})
With the clientIds of the accessibleClients array, i create an object of DocumentSnapshots with the clientId as property key.
The snapshot callback function pushes the specific client data into the clientDataArray. If a snapshot changes the callback function replaces the old data with the new data.
I do not know your exact data model but i hope this code helps with your problem.

Get the ChildrenCount of a child in Firebase using JavaScript

I have been doing this for an hour. I simply want to get the number of children in the child "Success" in the database below. The answers in similar stackoverflow questions are not working. I am new in Javascript Programming.
So far I have tried this
var children = firebase.database().ref('Success/').onWrite(event => {
return event.data.ref.parent.once("value", (snapshot) => {
const count = snapshot.numChildren();
console.log(count);
})
})
and also this
var children = firebase.database().ref('Success/').onWrite(event => {
return event.data.ref.parent.once("value", (snapshot) => {
const count = snapshot.numChildren();
console.log(count);
})
})
Where might I be going wrong.
As explained in the doc, you have to use the numChildren() method, as follows:
var ref = firebase.database().ref("Success");
ref.once("value")
.then(function(snapshot) {
console.log(snapshot.numChildren());
});
If you want to use this method in a Cloud Function, you can do as follows:
exports.children = functions.database
.ref('/Success')
.onWrite((change, context) => {
console.log(change.after.numChildren());
return null;
});
Note that:
The new syntax for Cloud Functions version > 1.0 is used, see https://firebase.google.com/docs/functions/beta-v1-diff?authuser=0
You should not forget to return a promise or a value to indicate to the platform that the Cloud Function execution is completed (for more details on this point, you may watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/).
const db = getDatabase(app)
const questionsRef = ref(db, 'questions')
const mathematicalLiteracy = child(questionsRef, 'mathematicalLiteracy')
onValue(mathematicalLiteracy, (snapshot) => {
const data = snapshot.val()
const lenML = data.length - 1
console.log(lenML)
})
This method worked for me. I wanted to get the children's count of the mathematicalLiteracy node in my database tree. If I get its value using .val() it returns an array that contains that node's children and an extra empty item. So, I subtracted that one empty item's count. Finally, I get my needed children's count.

Categories

Resources