REALM MOBILE PLATFORM sync problems resolution - swift3

I have linked list in Realm DB like
ABCD
Each item is Realm object like
{name,next item}
So if I change list on device 1 offline to
ACBD
and on device 2 to
ADBC
and sync after that I get synced DB but wrong cycled list
A -> D -> B -> D .....
How can I solve this problem?
Is there possibility to get synced objects after sync on clients and to correct lists before realm Results notifications will be launched?
Update.
I also tried to use such model for hierarchical lists
class MList: Object {
dynamic var name = ""
let items = List<MItem>()
}
class MItem: Object {
dynamic var name = ""
let subitems = List<MItem>()
}
I have used data
A
B
1.
A
-B
2.
B
-A
After sync but list lost all items. So such data struct is unsuitable for my task.

Alright, I see the problem.
Manually maintaining a linked list structure unfortunately won't work, because Realm sees each link update as a regular property update without knowledge about the item's position in the list. Therefore the list updates cannot be merged in the expected way when multiple participants update the list, and the result will be duplicates, cycles, or leaked objects.
Instead, I suggest you use Realm's built-in list type, which will merge correctly. You will still have a problem related to the parent field in your data model, whereby if two participants change the value, the last one to do so will "win". I'm not sure what your exact use case is, so this may or may not be fine. Notably it probably won't be fine if you perform tree rotations, in which case you will end up leaking objects from the graph or creating unexpected cycles.
The best long-term solution is for Realm to introduce a proper CRDT tree type, but so far there hasn't been demand for this. If trees are a fundamentally requirement in your data model, I suggest creating a feature request for CRDT trees in our GitHub repository.

Can you use Realm's own lists? They have quite an elaborate merging logic that supports element moves/reorderings: https://realm.io/docs/javascript/latest/#list-properties

Now I have the model
class MList: Object {
dynamic var name = ""
dynamic var firstItem: PLItem?
}
class MItem: Object {
dynamic var name = ""
dynamic var next: PLItem?
dynamic var parent: PLItem?
}
I use "next" to order list and "parent" to create the tree structure.

Related

Ember data store handling array of objects

I'm new to ember and exploring its capabilities by building a small module. I came across a scenario where I need to update the ember model content synchronously. The ember-data model contains an array of objects as contents.
I was hoping to perform a few tasks as follows
Perform an array content reorder - for the sake of simplicity we
can assume swapping the first and last item.
Append a record
without a network call
Delete a record without a network call.
Doing these should automatically sync the data bindings/computed props
My data model after a peekAll call contains 10 records(shown below) on which I need to perform the above operations.
My model is as shown below
export default Model.extend({
testId: attr('number'),
name: attr('string')
});
What is the right approach to update the content record? Could someone please suggest how to proceed?
This looks to me like the results of running something like let arr = await store.findAll('test-model'), is that correct? This is probably a PromiseArray and you can access the data as a Javascript Array by calling arr.slice() on it. This will let you do normal array operations, though performing a content re-order doesn't really make much sense in this scenario. I assume you were using it as an example.
For adding and removing records without a network call you can do that by going back to the store and this is what is covered in the docs, you don't need to act on this Object you're looking at.
Adding a new record:
let testModel = store.createRecord('test-model', {
name: 'Lorem ipsum'
});
testModel.save(); //until you do this no network data will be sent
Removing a record:
let testModel = store.peekRecord('testModel', 1); //to get a record with ID of 1
testModel.deleteRecord();
testModel.save(); //until you run save no network is sent
Once you've taken action like this on the store the data structure you posted above may be updated to contain the new data depending on how you accessed it originally. You can also re-fetch data from the store which will now know about your adding a deleting of models (even though you haven't saved it back to the server yet)
If you haven't saved yet and you re-do a peekRecord you'll need to filter out any deleted records from the results.
let undeletedModels = this.store.peekAll('test-model').filter(m => !m.isDeleted);

What are the trade-offs in Cloud Datastore for list property vs multiple properties vs ancestor key?

My application has models such as the following:
class Employee:
name = attr.ib(str)
department = attr.ib(int)
organization_unit = attr.ib(int)
pay_class = attr.ib(int)
cost_center = attr.ib(int)
It works okay, but I'd like to refactor my application to more of a microkernel (plugin) pattern, where there is a core Employee model that just might just have the name, and plugins can add other properties. I imagine perhaps one possible solution might be:
class Employee:
name = attr.ib(str)
labels = attr.ib(list)
An employee might look like this:
Employee(
name='John Doe'
labels=['department:123',
'organization_unit:456',
'pay_class:789',
'cost_center:012']
)
Perhaps another solution would be to just create an entity for each "label" with the core employee as the ancestor key. One concern with this solution is that currently writes to an entity group are limited to 1 per second, although that limitation will go away (hopefully soon) once Google upgrades existing Datastores to the new "Cloud Firestore in Datastore mode":
https://cloud.google.com/datastore/docs/firestore-or-datastore#in_native_mode
I suppose an application-level trade-off between the list property and ancestor keys approaches is that the list approach more tightly couples plugins with the core, whereas the ancestor key has a somewhat more decoupled data scheme (though not entirely).
Are there any other trade-offs I should be concerned with, performance or otherwise?
Personally I would go with multiple properties for many reasons but it's possible to mix all of these solutions for varying degree of flexibility as required by the app. The main trade-offs are
a) You can't do joins in data store, so storing related data in multiple entities will prevent querying with complex where clauses (ancestor key approach)
b) You can't do range queries if you make numeric and date fields as labels (list property approach)
c) The index could be large and expensive if you index your labels field and only a small set of the labels actually need to be indexed
So, one way to think of mixing all these 3 is
a) For your static data and application logic, use multiple properties.
b) For dynamic data that is not going to be used for querying, you can use a list of labels.
c) For a pluggable data that a plugin needs to query on but doesn't need to join with the static data, you can create another entity that again uses a) and b) so the plugin stores all related data together.

I can't directly cast object in my Entity Framework query using ValueInjecter

I'm trying to use ValueInjecter to map my entities to my DTOs in my asp.net core project.
Could someone explain me why this works:
var list = _context.Assets
.ToList();
var vm = list
.Select(a => new ViewModel().InjectFrom(a))
.Cast<ViewModel>()
.ToList();
return vm;
But this doesn't:
var list = _context.Assets
.Select(a => new ViewModel().InjectFrom(a))
.Cast<ViewModel>()
.ToList();
return list;
Is this a ValueInjecter bug? Am I doing something wrong?
Would Automapper solve this? I strongly prefer valueinjecter syntax compared to Automapper.
Thanks for your help!
Edit:
#Chris Pratt: Thanks for your quick answer. But why would it work when I map properties manually like the example below. I'm still applying this mapping to the IQueryable interface not in-memory.
Then why this works?
var vm = _context.Assets
.Select(a => new ViewModel
{
Id = a.Id,
Code = a.Code
})
.AsNoTracking()
.ToList();
return vm;
I haven't used ValueInjector, but my guess is that it comes down to the Select being applied in-memory in the first example and to the query in the second example. Dynamic mapping is not something that can be done at the database level, and specifically, EF must be able to translate the things you pass in Select, Where, etc. into SQL. It will not be able to do so with the ValueInjector code, and hence cannot construct a query to satisfy the LINQ expression. You do not have this issue in the first example, because you pull then entities from the database first, and then you map those in-memory instances.
For what it's worth, AutoMapper would have the same problem here, so it's not technically a mapping provider problem - just one of where the operation is going to be run (i.e. in-memory vs. at the database).

couchdb mapreduce query intersection of multiple keys

I'm manipulating documents containing a dictionnary of arbitrary metadata, and I would like to search documents based on metadata.
So far my approach is to build an index from the metadata. For each document, I insert each (key,value) pair of the metadata dictionary.
var metaIndexDoc = {
_id: '_design/meta_index',
views: {
by_meta: {
map: function(doc) {
if (doc.meta) {
for (var k in doc.meta) {
var v = doc.meta[k];
emit(k,v);
}
}
}.toString()
}
}
};
That way, I can query for all the docs that have a metadata date, and the result will be sorted based on the value associated with date. So far, so good.
Now, I would like to make queries based on multiple criteria: docs that have date AND important in their metadata. From what I've gathered so far, it looks like the way I built my index won't allow that. I could create a new index with ['date', 'important'] as keys, but the number of indexes would grow exponentially as I add new metadata keys.
I also read about using a new kind of document to store the fact that document X has metadata (key,value), which is definitely how you would do it in a relational database, but I would rather have self-contained documents if it is possible.
Right now, I'm thinking about keeping my metaIndex, making one query for date, one for important, and then use underscore.intersection to compute the intersection of both lists.
Am I missing something ?
EDIT: after discussion with #alexis, I'm reconsidering the option to create custom indexes when I need them and to let PouchDB manage them. It is still true that with a growing number of metadata fields, the number of possible combinations will grow exponentially, but as long as the indexes are created only when they are needed, I guess I'm good to go...

List updating when shouldnt?

I am using a static class in my application. It basically uses an access database, and copies itself to various lists.
When the user modifies some data, the data is updates in the list, using LINQ, if there is no entry in the list for the modification then it will add a new item to the list.
This all works fine.
However on the 1st data interrogation, I create the original list, basically all records in the users table, so I have a list lstDATABASERECORDS.
What I do after populating this list I do lstDATABASERECORDSCOMPARISON=lstDATABASERECORDS
this enables me to quickly check whether to use an update or append query.
However when I add to lstDATABASERECORDS a record is added in lstDATABASERECORDSCOMPARISON too.
Can anyone advise?
You are assigning two variables to refer to the same instance of a list. Instead, you may want to try generating a clone of your list to keep for deltas (ICloneable is unfortunately not that useful without additional work to define cloneable semantics for your objects), or use objects that implement IEditableObject and probably INotifyPropertyChanged for change tracking (there's a few options there, including rolling your own).
There's nothing built in to the framework (until EF) that replicates the old ADO recordset capability to auto-magically generate update queries that only attempt to modify changed columns.