i'm trying to delete an specific object from an array in Firestore via SwiftUI. The following function deletes the whole watchlist. What am I missing?
func removeFromWatchlist() {
if let uid = Auth.auth().currentUser?.uid {
let docRef = db.collection("user").document(uid) // company.symbol = "AAPL"
docRef.updateData(["watchlist": FieldValue.arrayRemove([company.symbol])]) { error in
if error == nil {
print("Successful deleted array")
}
}
}
}
And here is my Firestore structure:
To remove an item from an array with FieldValue.arrayRemove you must specify the exact, complete data that is stored in the array.
Assuming your company.symbol is AAPL, the call FieldValue.arrayRemove([company.symbol] removes that exact string from the array - not the AAPL key that you have with an object under it.
You'll have to read the entire array from the document into you application code, remove it there, and then write the entire modified array back to the document.
Related
I am using a scheduled task in a Firebase Cloud Function to query an array which contains a number of objects that need to be updated if a matching condition exists. My current attempt is using the 'array-contains' method to get the objects, then loop over them to find a matching condition which will then batch update the items. This is my data structure:
I need to find an object that is <= the current time, and also if the 'active' value = false.
export const liveMeetingsTrigger = functions.runWith( { memory: '1GB' }).pubsub
.schedule('every 1 minutes').onRun(async context => {
const now = admin.firestore.Timestamp.now();
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
const batch = admin.firestore().batch();
liveMeetings.forEach(doc => {
if(doc.data().liveMeetingDate <= now && doc.data().active == false){
batch.update(doc.ref,'active',true);
}
});
return await batch.commit();
});
I have also tried using an exact object in the query instead of just using 'liveMeetingDate', but still get no results back, any help would be great - thanks.
Debugging: As the array I am trying to reach is inside of the (map) object 'liveMeetings' i have tried the dot notation (liveMeetings.meeting) with no success. Also trying a new collection with the the 'meeting' array at top level has provided no success.
Simple logging in the console (liveMeetings.size) shows that nothing is being returned on the query, so therefore the logging does not even reach the loop in the code.
As explained in this anwser the following query will not work:
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'liveMeetingDate').get();
because the meetings array contain some objects, instead of "simple" or primitive data (e.g. string, number...).
You could query it with the exact objects, like:
const obj = {active: false, liveMeetingDate: ..., meetingId: ..., ....};
const liveMeetings = await admin.firestore().collection('fl_content').where('meeting', 'array-contains', 'obj').get();
Another approach would be to create a new collection which contains the similar documents (same Document ID) but with a meeting Array that contains only the liveMeetingDate property.
Finally, note that since your Array is within a map, you need to do
await admin.firestore().collection('fl_content').where('liveMeetings.meeting', 'array-contains', ...).get();
(PS: I don't mark this question as duplicate since you expressly ask for more help in the comments of the duplicate question/answer)
I was struggling yesterday to handle in a SWIFT app a Firestore map object that had a variable size so I though to share my solution.
The document contained a map like this:
{"07:45"=9;"09:56"=4;"13:12"=16}
The problem was that there could be more or less fields and the field names are unknown in advance, so it was not possible to know how many elements there were or even the names of the fields. For this reason I couldn't address the fields directly by just reading it into a dictionary. On top of that, as dictionaries is not ordered, I couldn't just address the elements in the dictionary by index.
I solved this by first reading the map into a dictionary, sorting it into an array, and then addressing the index of the array I wanted.
db.document(eventID).getDocument{ (document, error) in
if let document = document, document.exists {
let let data = document.data()
let timeslots = data!["times"] as! Dictionary<String, Int>
let self.count = timeslots.count. // To use elsewhere
let sortedTimes = self.timeslots.sorted(by: { $0.0 < $1.0 }) // Sort by key value which contains times as strings.
print(sortedTimes[0].value) // Just to print the value of the first tuple. NB sortedTimes is an Array of key,value pairs.
} else {
print("Document does not exist")
}
}
Function executes when a write is made in collection logs, it checks if doc exists in collection totals. If doc exists it is trying to update number object with number+1 at [0] of array.
Here is my code:
...//some code
var washingtonRef = admin.firestore().collection('totals').doc(entryDate_show);
washingtonRef.get().then((doc: any)=> {
if (doc.exists) {
console.log("doc found");
console.log("Document data:", doc.data());
washingtonRef.update({
[auth_ID]: admin.firestore.FieldValue.arrayUnion(
{ number: doc.data().number+1, // here it is trying to do +1
fullname: fullname,
authid: auth_ID },
)
});
...//some code
Problem: It is not working as expected
In array, it is adding new object [1] with number : NaN
Expected behaviour: number : 2 at [0]
Attaching pic of the console:
FieldValue.arrayUnion() adds a new element to an array field. That's why you're seeing a new object.
Firestore provides no update operation that uses the index of an array item to modify it. If you want to update an item in an array by index, you have to read the document, modify the array in memory, then update the array field back to the document.
I have a list of a document ids and I want to fetch the data of those documents from Firestore and display it using the FutureBuilder.
contestList = [awebnmsdfjkeeer23,324cdas4asdf, 34sdfasgadsg]
Future<void> fetchUsergameData() async {
contestList.forEach((element) async{
await Firestore.instance.collection('LiveGames').document('$element')
.get().then((dss) {
if(dss.exists) {
tempgame.add(dss.data["GameData"]);
temproom.add(dss.data["Room"]);
temptitle.add(dss.data["Title"]);
temp = tempgame + temproom + temptitle;
joinedContests.add(temp);
}
}).then((value) => {});
});
print(joinedContests);
}
}
I have used the above function to get the data and try to store in the list, like one document data in list. But i am getting the blank list of the data. How to get the whole document and display it using the FutureBuilder in flutter
It looks like you have multiple different issues on your code:
contestList has invalid keywords. 324cdas4asdf and 34sdfasgadsg are not valid variable names as they both start with a number, which is not a valid variable name. If they are supposed to be the ids that you want to retrieve they must be enclosed by ", which will make them strings.
You are trying to access the document using '$element' as if it were a bash variable, but there are two problems there: it's not done like that and there no need to do it. element already holds the value as a string so it just has to be accessed as is.
You are calling the method then twice without doing anything the second time. This shouldn't be a concern, but it simply doesn't do anything and can me omitted.
Below you will see an edited version of your code fixing all the aforementioned mistakes.
contestList = ["awebnmsdfjkeeer23", "324cdas4asdf", "34sdfasgadsg"]
Future<void> fetchUsergameData() async {
contestList.forEach((element) async{
await Firestore.instance.collection('LiveGames').document(element)
.get().then((dss) {
if(dss.exists) {
tempgame.add(dss.data["GameData"]);
temproom.add(dss.data["Room"]);
temptitle.add(dss.data["Title"]);
temp = tempgame + temproom + temptitle;
joinedContests.add(temp);
}
});
});
print(joinedContests);
}
}
On another note, it's unknown to us the type of tempgame, temproom and temptitle but judging by how you are accessing it you may simply want to do something like this:
tempgame = dss.data["GameData"];
temproom = dss.data["Room"];
temptitle = dss.data["Title"];
temp = tempgame + temproom + temptitle;
joinedContests.add(temp);
I am trying to iterate over firebaseObject and firebaseArray fetched from my Firebase but they don't seem like normal javascript objects and arrays.
My data is stored in the following form
'mainKey': {
'key1':'value1',
'key2':'value2'
},
'mainkey2': {
'key3':'value3'
}
I've tried the following code
var firebaseRef = new Firebase("https://<my-app>.firebaseio.com/);
var fbArray = $firebaseArray(firebaseRef);
var fbObject = $firebaseObject(firebaseRef);
for(var i=0;i<fbArray.length;i++){
console.log(fbArray[i]);
}
console.log(fbObject);
console.log(fbObject.mainkey);
console.log(fbArray.length);
This gives the following output in the console
Object { $$conf={...}, $id="test", $priority=null, more...}
undefined
0
Though the object returned has mainkey property but I'm not able to access it.Why does this happen? And how should I iterate over them ?
You could try for..in loop to iterate over an object.
Below is an example:
for (var key in fbObject) {
console.log(fbObject[key]); // You could use this method with all objects in JS
}
here's the info you need to know
The $firebaseArray service takes a Firebase reference or Firebase Query and
returns a JavaScript array which contains the data at the provided Firebase
reference. Note that the data will not be available immediately since
retrieving it is an asynchronous operation.
You can use the $loaded() promise to get notified when the data has loaded.
https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray
fbArray.$loaded(function() {
//here you can iterate over your object
});