Reputation: 10930
I'm trying to update a property in a record in Firebase Database, with AngularJS. I can set up a query to find my record:
firebase.database().ref('en/').orderByChild('word').equalTo('the').once('value')
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
console.log(childSnapshot.val())
});
})
I can update my property, if I hardcode in the record's key:
firebase.database().ref('en/-KloeQHDC-mugPjJMAG4').update({ wordFrequency: 111 })
But if I set up a query to find the record and then update it, I get an error message update is not a function
:
firebase.database().ref('en/').orderByChild('word').equalTo('the').update({ wordFrequency: 9001 })
Another answer suggests calling update()
from inside a forEach
loop:
firebase.database().ref('en/').orderByChild('word').equalTo('the').once('value')
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
console.log(childSnapshot.val()); // this works
childSnapshot.ref().update({ wordFrequency: 9001 });
});
});
That returns an error message TypeError: childSnapshot.ref is not a function
. I don't see how childSnapshot
is a Firebase ref.
Another answer says
When you call update() on a location, Firebase loops over the data that you pass in (in your case asJson) and for each key performs a ref.child(key).set(value).
If update()
loops over the data, why should I call update()
from inside a forEach
loop? The documentation doesn't show calling update()
from inside a forEach
loop.
Upvotes: 1
Views: 4862
Reputation: 10930
After I posted this question I walked the dog, ate dinner, and then the solution came to me. My new rule is, "The key to Firebase queries is to keep track of the key."
This template is for users to update records in the database. They enter a search term in a form field and click the "Search" button. The $scope.search
handler queries the Firebase database and then populates the form fields with the record's properties:
$scope.search = function() {
myFirebase_ref.orderByChild('word').equalTo($scope.word).once('value')
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
$scope.wordKey = childSnapshot.key;
$scope.audioArray = childSnapshot.val().audio;
$scope.ipaArray = childSnapshot.val().ipa;
$scope.language = childSnapshot.val().language;
$scope.longLanguage = childSnapshot.val().longLanguage;
$scope.phonemeArray = childSnapshot.val().phonemes;
$scope.translationArray = childSnapshot.val().translations;
$scope.word = childSnapshot.val().word;
$scope.wordFrequency = childSnapshot.val().wordFrequency;
$scope.$apply();
});
})
.catch(function(error) {
console.error("Authentication failed:", error.message);
});
};
Note at the top of the property assignments I have $scope.wordKey = childSnapshot.key;
. I'm keeping track of the record's key.
The user then updates a field. Each field has a button next to it for "Update". Each button goes to a handler. For example, to update the wordFrequency
field I have this handler:
$scope.updateFrequencyRank = function() {
firebase.database().ref('en/' + $scope.wordKey).update({ wordFrequency: $scope.wordFrequency })
};
One line of code and it works! Even better, I made an onComplete
function to tell me if the update succeeded:
$scope.updateFrequencyRank = function() {
var onComplete = function(error) {
if (error) {
console.log('Update failed');
} else {
console.log('Update succeeded');
}
};
firebase.database().ref('en/' + $scope.wordKey).update({ wordFrequency: $scope.wordFrequency }, onComplete);
};
Upvotes: 1
Reputation: 598708
The Firebase Database SDK provides a Reference.update()
method to update data in a single location in a database. Key here is that a Reference
is a single location in the database, so it is clear what to update.
My pseudo-code explanation about how multi-path updates work applies to how the database server implements it: given a single location/DatabaseReference
it updates each path in the update()
call based on that.
A Query
can match multiple locations in the database, so it doesn't have an update()
method (or set()
or remove()
for that matter).
To update each location matched by a query, you execute the query and then call update()
on each result - either by a child_added
listener, or with a value
listener and a loop like in your last snippet.
Upvotes: 3