Realm Swift inverse relationships many-to-many - swift

I'm currently trying to work out the best way to architect my realm objects for ease of retrieval.
I have 2 objects tags and object there are multiple tags and each one might contain many object. Similarly each object could have multiple tag associated with it
Ideally selecting a single tag should retrieve all object that have at least that one tag (but could obviously have multiple)
would my models be specified as
class Tag: Object {
let objects = List<Object>()
}
class Object {
let tags = List<Tag>()
}
I don't think I need to use an inverse relationship here or should I? Choosing a Category I should be able to just retrieve a list of all object references regardless, but then maintaining and updating the references to an object might be difficult here? I.e a user selects tag 'A' then updates the first object to also include tag 'B' I would need to update the object in the List for Tag A, then add a new item to the list for Tag 'B' and finally update the actual Object itself to include Tag 'B' in it's list of tags.
Just to be clear an Object will only ever display and allow editing of it's Tag objects. But the Tag object itself will need to know what Object's are applicable to it.
However it feels like I will have to do multiple updates when ideally I'd like to minimise this effort. Can anyone recommend a better way to do this? Or is there no way around this due to the limitations of Realm?

This is exactly what LinkingObjects is for. Changing the objects property in Tag to let objects = LinkingObjects(fromType: Object.self, property: "tags") will make it automatically update whenever a tag is added to an object.

Related

How can I reorder elements in Realm LinkingObjects?

I have an Item data class, and each Item has one parent and many children Items, which are LinkingObjects from the parent property.
A simplified version:
#objcMembers class Item: Object {
dynamic var title: String = ""
dynamic var parent: Item?
let children = LinkingObjects(fromType: Item.self, property: "parent")
}
I need to be able to reorder the children, and persist that change. It seems that because LinkingObjects is a container type this wouldn't be possible? In this case, how would you recommend I approach this--should I change children to a normal List<Item> and just manually update the realm two ways every time? Is there a better solution?
The order in which the children appear matters, because users will want to choose their own ordering based on which items they want to see first.
The important part here is that you want to control the 'order in which the children appear'. If you can recognise the difference between the 'model' of the data and the 'view' of the data then you can work out the answer. Remember that the Realm model representation is not under your control, and you don't need it to be. How it's stored in the Realm database is not your problem.
In reality, the results of the LinkingObjects field when you request it will probably be the result of a database query, and not a straight pull from a table. So the order of objects in the field may be inconsistent, or adding further linked objects may cause the extra item to appear anywhere in the results.
As you say, the important thing is the order in which the children appear. And this can be controlled through a query. The LinkingObjects type allows you to query directly, i.e. you can call:
item.children.sorted(byKeyPath: "title")
One suggestion would be to add an extension to your model type to handle the sorting for you, providing an accessor for each sort type you require, e.g.:
extension Item
{
var childrenSortedByTitle: Results<Item>
{
return children.sorted(byKeyPath: "title")
}
}
Or you could make that a function with an ascending boolean parameter to use in the query. Or you could add a second query for ascending/descending. And you can add extra queries for each other parameter you would like to sort by. Or you could define an enum of sort fields and pass that it as an argument. Whichever of these methods works best for you. But it is definitely worth hiding the query details in the class extension itself (IMHO).

MongoDB storing and querying child objects

I've two different object with same father. I want to store them in the same collection, but I want to be able to retrieve each object separately.
for example if these are my objects:
I want to retrieve all of FirstChild objects without retrieving any SecondChild Object.
Is there any way other than adding a type field to the father object, to retrieve them?
Assuming first child and second child are different types stored in different fields of the father object (father is a composition of first and second child)
datastore.find(FatherObject.class).retrievedFields(false,"secondChildField")
will get everything except secondChildField or
datastore.find(FatherObject.class).retrievedFields(true,"firstChildField")
will bring only firstChildField.
When you create your query, pass in the class reference of the type you want: datastore.createQuery(SecondChild.class). Morphia, by default, tracks the class type of the document so it can filter by that type.

Can you obtain an unique identifier for a MATLAB object?

I am debugging some MATLAB code, and want to make sure that two references to an object are actually referring to the same object. Is there a way to obtain a unique identifier for the objects (such as a memory address)?
As far as I know I am not able to add my own IDs to the objects, as they are MATLAB random number streams.
If you are using OOP then you could add a property ID and set it during the construction of the object.
java.rmi.server.UID() is a nice way to obtain unique ID's
However testing by == will check the actual handles, so this is more of a usability issue.
classdef yourClass < handle
properties
ID
end
methods
function obj = yourClass()
obj.ID = java.rmi.server.UID();
end
end
end
It will then be rather simple to check your objects.
If the objects you're wanting to compare are MATLAB random number streams (i.e. they are of class RandStream), then they are handle objects. In that case you don't need unique IDs: if you compare them using eq or == and they are equal, then they are the same object.
As you say, you are not able to add your own properties to an object of class RandStream, but if you really wanted to you could subclass RandStream and add a property of your own to the subclass. You could store a unique identifier in the property, generated with char(java.util.UUID.randomUUID).
You can use the UserData field, which is present in every graphical object, to store a unique identity generated by you. If working with a user-defined class, you can add a similar field in your class.
The identities can be kept unique by using a global counter to assign each new identity.

In Tastypie is there a way to change a resources excludes based on the authentication?

Consider the example of a user resource that has profile pic and email fields. Where any user may see any other users profile pic but a user may only see their own email address.
Is it possible to setup tastypie so that the set of excluded fields can be varied based on the authenticated user?
I realize that an alternative approach is to create separate full and restricted user resources. But for the moment I just want to know whether the approach of limiting the fields based on user authentication is even doable in tastypie.
Also it doesn't have to be the excludes, in the same vein is there a way instead to change the fields property based on the requesting user?
I dont think excluded fields can be brought back into the picture in an elegant fashion. You could probably manipulate the object list based on the request using some object manipulation by including the get_object_list in your resource
But it would be much better and more logical for you to use the apply_limits method in your custom authorization class.
Yes there is a way to do it.
If you define email to be a separate field, not the one of the User(might work and with that but never did it).
You can define dehydrate_email where the bundle.request contains the current request and you could get it. It won't be exactly excluded as a field but it will be None for others.
I created a ModelResource subclass that can be multiple inherited into the required ModelResource instances. Like:
class ResourceThatNeedsToExcludeSomeFields(ExcludeResource, ModelResource):
pass
It takes in the fields to be excluded via GET parameters (like "&exclude=username")
class ExcludeResource(ModelResource):
"""
Generic class to implement exclusion of fields in all the ModelResource classes
All ModelResource classes will be muliple inherited by this class, whose dehydrate method has been overriden
"""
# STACK: How to exclude some fields from a resource list created by tastypie?
def dehydrate(self, bundle):
# I was taking the exclude fields from get paramaters as a comma separated value
if bundle.request.GET.get('exclude'):
exclude_fields = bundle.request.GET.get('exclude').split(',')
for field in exclude_fields:
if str(field) in bundle.data.keys():
del bundle.data[str(field)]
return bundle
You can modify this to get the exclude fields based on user group (or whatever criteria you base the fields on) like this:
class ExcludeResource(ModelResource):
"""
Generic class to implement exclusion of fields in all the ModelResource classes
All ModelResource classes will be muliple inherited by this class, whose dehydrate method has been overriden
"""
# STACK: How to exclude some fields from a resource list created by tastypie?
def dehydrate(self, bundle):
exclude_fields = <get a comma separated list of fields to be excluded based in bundle.request.user>
for field in exclude_fields:
if str(field) in bundle.data.keys():
del bundle.data[str(field)]
return bundle
However, this snippet will not work for related resources specified with "full=True"

Can I tell Core Data to use a specific unique ID for an y object when saving it?

Example: I read data from an XML file. This data has unique id elements. I want to store those objects with their original unique id. How would I do that?
I figured out I could ask the managed object for it's ID, like this:
NSManagedObjectID *moID = [managedObject objectID];
but here the problem is: The XML tells me with the id element which object this is, and I need to look up in the database of core data if this object already exists in there, or not. So is it the only option to make an id attribute in my managed object model for that entity and then query for that? Then I will have two id systems right?
Don't worry about the ObjectID of Core Data. This is an internal unique ID which is not guarantied to be constant during the object's life cycle (e.g. it will change when you save the object to sql store). Just create a new mandatory attribute in your model and flag it as indexed so retrieval will be fast.
In the entity associated to this kind of objects, simply add another attribute of type string, call it objectID or similar and declare it to be mandatory.