When I try to save data to Firebase it only updates the existing data, Swift, Firebase - ios

The way I set up my database structure was like this:
It starts with Lists then there is a child that shows the users UID then inside that there is one item.
The one item inside the UID gets updated every time I attempt to save new data. Instead of adding another item the same one just keeps changing. I was wondering how I could instead of update the same one item every time add more items.
The way that I save my data is with this line of code.
let user = FIRAuth.auth()?.currentUser
let item: String = self.ItemTextField.text!
self.ref.child("Lists").child(user!.uid).setValue(["Items": item])

More idiomatic is to store the list of items with so-called push ids:
Lists
twEymn...
-Km....: "Yoghurt"
You'd do this with:
self.ref.child("Lists").child(user!.uid).childByAutoId().setValue(item)
The childByAutoId() generates a unique, sequential ID. It's similar to an array index, but this one works reliably in multi-user environments and when users can be offline. Read this blog post about these so-called push ids.
Alternatively you can use the name of the item as the key (if the item has to be unique in the list):
Lists
twEymn...
"Yoghurt": true
In that case the code becomes:
self.ref.child("Lists").child(user!.uid).child(item).setValue(true)
One thing you'll note is that both of these approaches only deal with the newly added item, instead of the list of items as a whole. This is a general pattern you'll see when using Firebase. By isolating your modifications, your app will be more scalable without users getting into each other's way.

The problem is that you are setting a key-value pair ("Items" : item) so that each time it is updating the value for the same key. What you could do instead is ("Items" : [your array of items here]), which will update a list of items for the same key each time.
You could also fetch the current list of items, append your new item locally, and then update.

Related

Microsoft Graph API remove Check List Item

I have a plannerTask and in its Details it has a CheckList. I use it to programatically insert CheckListItems in it, and it all works like a charm when inserting or retrieving the tasks.
My problem arrives when I am going to insert a new CheckListItem and the CheckList already has 20 items. It returns a MaximumChecklistItemsOnTask (because it is forbidden to insert more than 20 items in a check list).
Solution could be to remove the oldest item, but I am not able to do it. I have tried this:
var elementToRemove = oldDetails.Checklist.Where(c => c.Value.IsChecked).OrderBy(c => c.Value.LastModifiedDateTime).First();
oldDetails.Checklist = oldDetails.Checklist.Where(c => c.Value.LastModifiedDateTime <> elementToRemove.Value.LastModifiedDateTime);
But it throws a casting error in the second line:
Unable to cast object of type
'WhereEnumerableIterator1[System.Collections.Generic.KeyValuePair2[System.String,Microsoft.Graph.PlannerChecklistItem]]'
to type 'Microsoft.Graph.PlannerChecklistItems'.
Which is the right way to remove the oldest element from the ChecklistItem?
UPDATE:
In first place I retrieve a plannerTask from the server. Then I get the details from this plannerTask. So oldDetails is a plannertaskdetails object (https://learn.microsoft.com/en-us/graph/api/resources/plannertaskdetails?view=graph-rest-1.0). Inside the plannertaskdetails object (oldDetails), I have the plannerchecklistitems object (oldDetails.Checklist): https://learn.microsoft.com/en-us/graph/api/resources/plannerchecklistitems?view=graph-rest-1.0.
If plannerchecklistitems were just a List, it would be as easy as list.Remove(item), but it is not a normal list, and that is why I am not able to remove the item.
UPDATE 2:
I have found this way to remove the item from oldDetails:
oldDetails.Checklist.AdditionalData.Remove(elementToRemove.Key)
But, the the way I send the changes to the server is this:
await graphClient.Planner.Tasks(plannerTask.Id).Details.Request().Header("If-Match", oldDetails.GetEtag).UpdateAsync(newDetails)
As it is a PATCH request (not a PUT one), I only have in newDetails the records that have changed, it is, the new records. How could I specify there that a record has been deleted from the list? Sorry if my English is not good enough to express myself properly, but what I mean is that newDetails is not the full list, it only contains the records that must be added and I do not know how to specify in that request that one record must be deleted.

Showing random data from core-data using Swift 3

I need some help getting random data from core data using Swift 3, Xcode 8.3.1. I currently have an app that creates a list in tableview using data that is entered by the user.. (user enters a name and takes a picture of that person) The entity "Friend" holds the attributes "name", "image".
The first version of this app was just a name and I would use arc4random to randomly update a label with a name on a modally presented VC on a button click. The names were simply stored in an Array.
This version is including an image so I decided to try my hand at core-data (never used it before) and now I'm stuck at my random select button. Currently the app will store the data fine and then retrieve it and display everyone alphabetically along with their image in a tableview. As a new person is submitted the info gets stored and the tableview updates.
I need to show a randomly selected name and its image, but I don't know how to do this and research has failed me on getting it done.
If there is a better way of storing an image & name instead of core-data I'm open to changing as well. The app stores anywhere from 20-80 different names. It will never be used to store much more than that.
You can fetch your items from the context, which will give you an array of objects. Now you just use your favorite random function to get a random index for this array. And then use an object at that index.

How to properly use createOrUpdateInRealm?

I am using Realm to handle persisting data to disk in my app. I am storing an ArticleCollection object to Realm (this just contains an array of NewsArticle objects).
I am using createOrUpdateInDefaultRealmWithValue to either create a new ArticleCollection or update the existing one (achieved using a primary key on ArticleCollection).
This currently works well when the app fetches new articles it will overwrite the current collection of articles and replace with a new instance of ArticleCollection.
The issue is that whilst ArticleCollection is replaced (in Realm brwoser I can see the count of ArticleCollection is always 1 as expected), the number of NewsArticles always increases. It seems that sub objects of ArticleCollection (NewsArticle) never get replaced/deleted, only appended to.
How can I ensure that when I use createOrUpdateInRealm, it will delete all sub objects?
Make sure that are also using a primary key on your NewsArticle object. Otherwise those news articles won't be updated. That's why you are seeing an increasing number of news articles.

Parse.com - Find deleted objects

I have an iOS app that synchronises to Parse.com.
It can find anything that was added to Parse and add it to Core Data using PFQuery. It can also check for any data that has been updated and update accordingly.
However, I'm not sure how to find objects that have been deleted on Parse.com.
Does anyone know of a query that will list the ObjectIDs that have been deleted and the date of their deletion? I can then remove them from the Core Data on the app.
I needed this function, too, but figured that marking rows as deleted will bloat the data and add a condition to every query. So I created a Deletion class. It records only the class name and ID of any deleted row, so it stays pretty small:
function recordDeletion(klass, identifier) {
var Deletion = Parse.Object.extend("Deletion");
var deletion = new Deletion();
deletion.set("klass", klass);
deletion.set("identifier", identifier);
return deletion.save();
}
// for every class that you want deletions recorded, add one of these...
Parse.Cloud.beforeDelete("MyClass", function(request, response) {
recordDeletion("MyClass", request.object.id).then(function() {response.success();});
});
My iOS clients record the date when they last fetched data, then get everything newly created/updated from MyClass (+ others) and Deletion. With that, the can delete the Deletions locally.
Over a longer period, the clients remove all of the locally cached data and get a fresh copy of everything (except Deletions). This allows me to have a scheduled job on the server that will empty the Deletion table (on a cycle that's much longer than the client's cycle).
There is no provided API for this.
As per the comment from #Fogmeister you can tag objects as deleted and update like that. Alternatively you can maintain a specific list of deleted ids (potentially using Parse.Cloud.beforeDelete) and then make a specific request to get only the deletions.
In either case you will need to explicitly manage the scheme you choose and also decide how and when to clean up the deleted objects / deletion records.

How to fetch all the Todo lists and its corresponding Todos for a project from New Basecamp (bcx) API

REFERRED https://github.com/basecamp/bcx-api/blob/master/sections/todos.md and https://github.com/basecamp/bcx-api/blob/master/sections/todolists.md
TRIED hitting the /todolists.json Basecamp bcx API (since I needed to show the todo lists as header/sections of the tableview displaying Project Todos).
GOT Names of the todo lists, their Descriptions (if any), and their respective URLs (amidst other not-so-useful-to-me info.)
Now, I have already used this URL (above) and hit it to fetch the list of todos (both completed and remaining) for that particular todo-list and got what I intended to; storing and displaying them, dynamically.
However, to me, this approach seems a bit amateurish as I am,a) storing the todo list in a mutable-array..b) hitting the API for each object of this mutable-array (above) and fetching an array of todos for a particular todo-list..c) storing this list (of todos) in a mutable-dictionary - key for which is the name of the todo-list..and finally,d) using this mutable-dictionary in the tableView:heightForRowAtIndexPath: and tableView:cellForRowAtIndexPath: methods for dynamically setting the tableView height and objects, respectively..
INTEND TO Get all the todo lists for a project WITH its corresponding todos as a response of a single Basecamp bcx API, for:
a) Improving the code quality,b) Decreasing the iteration time,c) Preventing headache of a person, if any, who is going to parse my code later in future
This currently isn't possible with the BCX API. If you want to see all of the todos on an individual project's todolists, you'll need to get each todolist separately.
I think this is probably available in the new API update. Kindly check.

Resources