I have a logic problem in my app using Parse, Regarding which path to choose to save in traffic, and if someone has already faced a similar problem, I will really appreciate the help. Also, you can end up helping other developers facing the same problem
I have a social app where there is a feed with objects, and users can bookmark ("favorite") these objects
I studied the Parse documents and concluded that among the pointers, relations and arrays, the best way to store favorite would be a objectId's array stored in the class of users. Each time an object is bookmarked by the user, the ObjectID of this object is stored in a objectID's array belonging to that user. The reason for the choice is:
It is easy to create the bookmark's view and show them to the user, since I just have to search for the user's ObjectID's array and finding those present in the class of objects
Saving only the objectID and not the entire object, I will save in traffic and I keep the app and traffic clean
But my logic problem is as follows. If user1 has created an object, and user2 bookmarked it, and then user1 decided to delete the object, I would have to search the objectID of this deleted object in each favorite array of each user!
So my question is, what would be less expensive for traffic of my App? Store the entire object when a user bookmark it, automating removal when a user deletes the object? Or just store the ObjectID, and perform the search on each array for each user when this object is deleted?
You can create Parse class for your feed objects. After that create an array column to store objectIds of users who added your feed item to favorit. When you want to find all the objects specific user bookmarked do something like
PFQuery *query = [PFQuery queryWithClassName:#"feedObjects"];
[query whereKey:#"favoritesArray" equalTo:#"YOUR USER OBJECT ID"];
[query findObjectsInBackground];
To remove object simply do
PFObject *feedItem = [PFQuery getObjectOfClass:#"feedObjects" objectId:#"ITEM TO REMOVE OBJECTID"];
[feedItem deleteInBackground];
Hope that helps :)
Related
I am trying to my data set to Core data. I could successfully save the data in coreData.
mY application have login. So, I need to save data against each user.
Now I visible the whole data foe every user.
Is there any idea for save user specific.
This is a job for your business logic.
One one hand, I suspect you have data that is available for everyone, you do not need to protect these.
For entities where the access should be restricted, you can store information about valid users or user groups in an attribute or a relationship. If you want to display a list of entities of that kind to the user, you have to fetch the data with some NSPredicate which gets you only the entities of the user, like so:
predicate = [NSPredicate predicateWithFormat:#"(user = %#) and (exampleAttr = 42)", currentUser];
My app's db has a many to many relationship between a Feed object and a Tweet object. This is to keep track of which feeds every tweet belongs in. If you're familiar with Twitter, imagine the main feed, a list feed, a user profile feed, etc.
How can I make a query using an NSPredicate to get a list of Tweets that exist in a specific Feed (and, inversely, get a list of Feeds that a Tweet exists in)? It seems that queries on inverse relationships does not work in Realm, so what are my options?
If I understand your question correctly this part of the documentation should be helpful:
Inverse Relationships Links are unidirectional. So if a to-many
property Person.dogs links to a Dog instance and a to-one property
Dog.owner links to Person, these links are independent from one
another. Appending a Dog to a Person instance’s dogs property, doesn’t
automatically set the dog’s owner property to this Person. Because
manually synchronizing pairs of relationships is error prone, complex
and duplicates information, Realm exposes an API to retrieve backlinks
described below.
With inverse relationships, you can obtain all objects linking to a
given object through a specific property. For example, calling
Object().linkingObjects(_:forProperty:) on a Dog instance will return
all objects of the specified class linking to the calling instance
with the specified property.
I guess you can do something like:
//assuming your Tweet object has a property like "let feeds = List<Feed>()"
someTweet.linkingObjects(Feed.self, forProperty: "feeds") //should return feeds your Tweet is in
But still I don't think I understand your question clearly. From my point of view your first requirement:
get a list of Tweets that exist in a specific Feed
should have a straightforward solution such as having a property in your Feed object like:
let tweets = List<Tweet>()
I wish you can clarify your situation further.
I wonder if it's possible to simplify the model a bit so many-to-many isn't necessary.
My understanding of Twitter is that tweets aren't 'owned' by any feeds. They simply exist on the platform, and are referenced by any number of feeds, but don't actually belong to any specific feed.
So a model setup like this should be appropriate:
class Tweet : Object {
}
class Feed : Object {
let tweets = List<Tweet>()
}
You can do a reverse lookup on a Tweet to see if there are any feeds in which it is currently visible, and you can simply use the tweets property of Feed objects to see which tweets they're displaying
Since the linkingObjects reverse lookup method of Realm simply returns a standard Swift Array, if you did want to filter that further, you could just use the system APIs (like filter or map) to refine it further.
Otherwise, if you really do want to be able to use Realm's NSPredicate filtering system both ways, then, as messy as it is, you would need to manually have each model linking to a list of the other:
class Tweet : Object {
let feeds = List<Feed>()
}
class Feed : Object {
let tweets = List<Tweet>()
}
While it's not recommended (Since it adds additional work), it's not disallowed.
Good luck!
The problem is that I want to get all of the objectIDs and I want to minimize data transfer in-between the server and iOS app. So, let's say I have a dozen of thousands of PFObjects on PARSE, they are updated and deleted and my app needs to update its knowledge about what objects are present on PARSE without using push-notifications (I am handling such a case when user disallows them). I can not just load all of the PFObjects every time my UIViewController presents data, retrieve PFObjects' ids and start checking whether my local store (not PARSE Local Datastore, different one) has such ids, since PFObjects themselves are large and there is a plenty of them, but it is ok for me to just load all of the objectIds. So, how to do this, and is it possible at all?
Some method of PFQuery like getAllObjectIds would be very helpful, but there seems to be no such methods.
You can solve the Add and Update situation but for the Delete its easier t use the straightforward solution and periodically request all object.
Here is a solution for the Update/Add object case:
and save the most recentUpdated Date
In the first request to parse set order object by updatedAt:
[query orderByDescending:#"updatedAt"];//orderByDescending
For any futur query set greaterThan:mostRecentUpdatedAt to get only updated and added objects:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"mostRecentUpdatedAt"]){
NSDate* mostRecentUpdatedAt = [[NSUserDefaults standardUserDefaults] objectForKey:#"mostRecentUpdatedAt"];
[query whereKey:#"updatedAt" greaterThan:mostRecentUpdatedAt];
}
save mostRecentUpdatedAt for futur queries:
if (results.count) {
PFObject* firtObj = [results firstObject];
NSDate* mostRecentUpdatedAt = firtObj.updatedAt;
[[NSUserDefaults standardUserDefaults] setObject:mostRecentUpdatedAt forKey:#"mostRecentUpdatedAt"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
For the Delete case you need a request to count the number or objects and compared to your count. this should be done immediately after checking for add/update since in this case if count mismatch then there is a delete situation. then get all objects again (no magic to be done to identify the deleted object since its already deleted!!).
You can not query the Parse DB for just the objectId's. You would have to pull the entire PFObject and then loop through and store just the id's and discard the rest.
Alternatively, I think you could create a PFRelation from the objects that you are interested in and the user to track just those objects.
i am trying to sync my project to parse. right now i am saving my data in core data. i have 2 kind of entities: Night and Session. it's look like this: Night have many session and session have one night.
when i want to add session to night i create or fetch night and add new session. this way i can get from my night all the session and the opposite way. in order to uploading it to parse i have added in the "Session" table "Night" column ( of type Pointer ) and in "Night" table i added "Sessions" column ( of type relation ) this is how it's look like:
i already succeeded to sync all the record from parse to Core data EXCEPT the relation and Pointers.
my problem is that the only solution for that ( insert this relation into core data ) is to create new night ( i mean create instance ) and create new sessions and add them like this:
-(void)addSession:(Session *)session toNight:(Night *)night {
if (session && night) {
NSMutableSet * sessionSet = [night.sessions mutableCopy];
[sessionSet addObject:session];
night.sessions = sessionSet;
}
}
So my Question is:
this is the only way? create instance and add them?
when i add Session to Night or when i add Night to session, why it's not shown in the DB table. i can not see this connection. ( like i see in parse ,relation and pointers)
when i get the Relation from parse it's look like this:
sessions = {
"__type" = Relation;
className = Session;
};
what i can do with that?
Thanks for reading this long Question and i hope i was clear :)
BTW: i follow this tutorial and they do not have relation and pointers.
Updatde
i am using Parse Rest Clint API.
this is the only way? create instance and add them?
yes. either you create a night object and set its sessions property; or you create a session object and set its night property. (provided you have defined and inverse in your core data model).
when i add Session to Night or when i add Night to session, why it's not shown in the DB table. i can not see this connection. ( like i see in parse ,relation and pointers)
this is not clear to me. What would you like to see in the DB table? if you add a bunch of sessions to a night, or you set the night property on session object, then when you inspect those object (reap. night - session) you can access the properties and should show the right value...
when i get the Relation from parse it's look like this:
In Parse, you do not need to model both the Pointer and the Relation (as it happens in Core Data where you have a relation and its inverse).
You just need the pointer for a one to many relationship. Parse relations are used from many to many relationships.
So, what you should to store all of the sessions in Parse is fetching them through a query like:
PFObject* night ...
PFQuery *query = [PFQuery queryWithClassName:#"Sessions"];
[query whereKey:#"night" equalTo:night];
then [query findObjects...] will give you an array of sessions you can add in a go to your Night Core Data object. (so, no need to call multiple time addSession:).
Hope this helps.
This is just answer to my first question: i follow this article and i found this quote:
Core Data cannot operate on data without loading the data into memory.
so i guess i solved my first question. Yes i have to load the data into my memory and then make the connection.
I have dug through a few of the tutorials at parse.com and I don't have a problem with users creating objects and storing them in Parse.
What I don't know how to do is passing an object to another user. So, for example, if I have users with their own to do lists, and a friend wants to add to another users' to do list, how would I go about doing that? So one user would create the object:
PFObject *task = [PFObject objectWithClassName:#"ToDo"];
[task setObject:#"Do the dishes" forKey:#"userName"];
[task save];
But I'd like this user to pass the task to a friend of theirs, so when their friend launches the app, they see the task added to their list.
I'm using the Facebook SDK as well, so if there's something there that could help, I could use that.
I haven't used Core Data before, so I was hoping to handle a lot of the backend work with parse so I could avoid the learning curve for the time being.
Thanks for all the help
I'd like to add that I'm not necessarily looking for an "answer". I just haven't done anything like this before so, I wouldn't know where to look.
You want to use user pointers & ACLs for this.
// assume PFUser *assigned
PFACL *acl = [PFACL ACLWithUser:PFUser.currentUser];
[acl setReadAccess:YES forUser:assigned];
PFObject *todo = [PFObject objectWithClassName:#"Todo"];
todo[#"task"] = #"Wash dishes";
todo[#"user"] = assigned;
todo.ACL = acl;
[todo saveInBackground];
Now, you can see all TODOs with
[PFQuery queryWithClassName:#"Todo"];
You can see all queries which are assigned to you with
[query whereKey:#"user" equalTo:PFUser.currentUser];
And only the creator of a TODO can edit it.
It seems that you have a many to many relationship here : a user can own many todo objects and a todo object can be own by many users.
This kind of approach can be handle with PFRelation object. Take a look at the official blog post here : http://blog.parse.com/2012/05/17/new-many-to-many/
I wouldn't handle it as a many to many relationship in this case.
The person who creates the todo object should be the only owner. You can add an attribute to the todo object and it's type can be an array. The array can then keep track of who it's shared with. If someone it's shared with deleted it you can then just remove them from the array or if the owner deletes it the object can just be deleted.