How can I reorder elements in Realm LinkingObjects? - swift

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).

Related

How to correctly handle simplified model in Fluent/Vapor?

Let's assume, I have a User model and this model contains products children (one to many relation).
In some situations, in my iOS app, I need only to display list with all users so I don't need to query my database about products.
How to preform, in the easiest way, fetching users without its children in Fluent?
Do I need to create a separate model that doesn't contain products?
func getAllUsersHandler(_ request: Request) -> EventLoopFuture<[User]> {
User.query(on: request.db).all()
}
The default situation is that a query on the User model will not include any Children fields in the result. To include them, you need .with(\.$products) in the query.
You can limit the fields returned by modifying your query as in the example:
User.query(on: request.db).field(\.$name).field(\.$email).all()
This only brings those fields into the model and leaves unwanted fields in an uninitialised state. See here for more information.

In Objection.js, what's the benefit of setting up relationMappings?

I'm kind of confused about what relationMappings do inside a Objection.js Model class.
I thought once we setup the relationMapping inside a Model, we will get related data in every query. But, it turns out that I still only the Model properties itself.
Is there anything else I should use to get related data in query?
Relation mappings gives model semantics how relations can be fetched when they are needed. It would be really bad for performance to always query all related rows in addition to main table's row. When you create relation mappings to model, you will not need to write joins manually every time you need to query relations. Also they enable many other objection features, which requires information how row relations goes in DB.
To use relation mappings in query Objection.js requires that within every query you must tell which relations you want to fetch with the main row with .withGraphFetched or .withGraphJoined methods https://vincit.github.io/objection.js/guide/query-examples.html#eager-loading
for example:
class Person extends Model {
static get tableName() {
return 'persons';
}
static get relationMappings() {
return {
pets: {
relation: Model.HasManyRelation,
modelClass: Animal,
join: {
from: 'persons.id',
to: 'animals.ownerId'
}
}
};
}
}
const people = await Person.query().withGraphFetched('pets');
// Each person has the `pets` property populated with Animal objects related
// through the `pets` relation.
console.log(people[0].pets[0].name);
console.log(people[0].pets[0] instanceof Animal); // --> true
Mappings are also used when you insert nested object data with .insertGraph so that related objects are inserted to related tables and foreign key references etc. are automatically filled according to relation mapping declarations.
There are many other places where those are used, but I hope this gives a rough idea why they exist.

Realm Swift inverse relationships many-to-many

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.

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.

entity framework wrong order of child object after some child objects detached

my problem is after first child object detached and then i add another child object to my parentObj the order of attached child is not correct
, my code look like this:
parentObj= new TparentObj();
firstChildObj=new Tchild1();
secondChildObj= new Tchild1();
thirdChildObj=new Tchild1();
parentObj.Tchild1.add(firstChildObj);
parentObj.Tchild1.add(secondChildObj);
// now parentObj.Tchild1.first()==firstChildObj return true
///then for some reason
parentObj.Tchild1.remove(firstChildObj);
db.Entry(firstChildObj).State = EntityState.Detached;
// now i add third childObj
parentObj.Tchild1.add(thirdChildObj);
//// now parentObj.Tchild1.first()==thirdChildObj return true!!
after saved db the result in database is Correct;
but how can i get list of childObj in order they added?
Entity Framework by default uses HashSets for its collections. HashSet doesn't take ordering into account.
You shouldn't rely on the ordering of elements for it. The current implementation seems (as you are experiencing) to add the element on the first unused position (in your case, the removed one), but this is an implementation detail and you shouldn't rely on it.
About HashSet, the MSDN says about it (bold is mine):
The HashSet class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
and
A HashSet collection is not sorted and cannot contain duplicate elements. If order or element duplication is more important than performance for your application, consider using the List class together with the Sort method.