Is there any way to transform Results into plain JavaScript object and array? I found out that I can use Array.prototype.slice.call(cars) to transform Results into array, but what about every item in the Results?
+1
@alazier Without this, lets say I have 2 models,
const CarSchema = {
name: 'Car',
properties: {
make: {type: 'string'},
model: 'string',
otherProp: {type: 'int', default: 0}
}
}
const PersonSchema = {
name: 'Person',
properties: {
cars: {type: 'list', objectType: 'Car'},
}
}
First, I create 5 cars. Then I create person with these cars, when I changed otherProp value within list, all cars updated. I don't want it. It should be default value for other users.
Can you share your code? It sounds like you may be creating 1 Car and adding that same car to a Person's list 5 times. If you did this, changing otherProp on one instance would change them for all 5 cars since all references in the list actually point to the same Car. If you are creating 5 different cars then the behavior you describe would be a bug in Realm.
Lets say, I have 100 Cars ( otherProp changes for each person). To one person, otherProp should be 1, to other person otherProp should be 2, for others It should be 0 which is default value. But If I set otherProp to 1 for one person, all other person's Car changed. I dont want it. I want to just use schema, not value. How can I do it ?
@alazier
Also, both schemas have primary key.
My models:
const KartelaSchema = {
name: 'Kartela',
primaryKey: 'art',
properties: {
art: 'int',
ey: {type: 'int', optional: true},
app_count: {type: 'int', optional: true, default: 0},
}
};
const DemandSchema = {
name: 'Demand',
primaryKey: 'idx',
properties: {
idx: 'string',
note: {type: 'string', optional: true},
items: {type: 'list', objectType: 'Kartela'},
}
};
Forexample, I get 10 Kartela items and change app_count value, then add it to Demand. Kartela items also updated. How do I prevent it ?
How do you create/get your Kartela objects? It sounds like you actually only have 1 Kartela which is added to Demand multiple times. Can you verify that each Kartela in the list have different primary key values?
@alazier Nope, I have 20k Kartela items with different primary key.
let kartela = realm.objects('Kartela');
initial state:
this.state = {
demand: {idx: "", note: "", items: []}
}
functions:
// _onAdd called many times
_onAdd(art){
var demand = this.state.demand;
let item = kartela.filtered('art = $0', art);
demand.items.push(item[0]);
this.setState({
demand: demand,
});
}
_save(){
var demand = this.state.demand;
demand.idx = Math.round(+new Date()/1000).toString();
DB.InsertDemand(demand);
}
InsertDemand(demand){
realm.write(() => {
realm.create('Demand', demand, true);
});
}
problem is here:
_handleCount(rowId, count){
var demand = this.state.demand;
demand.items[rowId].app_count = count
this.setState({demand: demand});
}
If I change app_count within Demand list, also Kartela item is updated. It should be 0 (or default value);
I think I understand now. What is going on is you are sharing Kartela instances between multiple Demands when really you want to be making a new copy.
To fix this you have two options.
First is to remove the primary key from Kartela and create a copy in _onAdd when you add to the list:
demand.items.push(realm.create('Kartela', item[0]));
You would need to remove the primary key as you can't have multiple objects with the same primary key.
The second option would be to separate out the count property on Kartela into to a wrapper object without a primary key:
const KartelaCount = {
name: 'KartelaCount',
properties: {
kartela: 'Kartela',
app_count: {type: 'int', optional: true, default: 0},
}
};
demand.items.push(realm.create('KartelaCount', {kartela: item[0]}));
This allows you to keep a primary key on Kartela if that is what you need, but is a bit more complicated.
Hmm, I choose second option :smile: Thanks!
@AwesomeJerry - to answer your original question:
You will need to convert each object individually, but you can do this recursively. If you have a simple schema without list or object properties you wont need the recursion. Something like the following would work for simple schema:
var plainResults = Array.prototype.map.call(resultsCars, (car) => {
var object = {};
for (var property of CarSchema.properties) {
object[name] = car[name];
}
return object;
});
It would be nice to be able to do this in a generic way but we are missing a few apis to make this possible. I created #332 to track the functionality required.
kk, thanks for answering! Will see what I can do.
@alazier what if I have a complex scheme (with list properties), should I need to write recursive code to persist to the db
@ismdcf - nested objects are added to the db automatically.
thanks @alazier it works, the fault was on my way of defining realm objects. but now I have the following Issue can you help me out with it Stack overflow question link
In my testing, the recursive method works fine, but is extremely slow when there are nested objects, even when they're only one layer deep. I've had much better performance with this:
function realmToPOJO(realmObject) {
return JSON.parse(JSON.stringify(realmObject));
}
Performance for the average object increased by ~50%. All my objects were at most one level nested.
@sampurcell93 on a small app the performance is not an issue hardly noticeable, but it works! Thanks
@sampurcell93 I tried doing the same in a react native app, but doesn't work for me.. my data still auto updates
I'm having the same issue. A method .toPlainObject() would be really useful.
@hussainb That's odd... make sure that you're operating on the thing returned from realmToPOJO - there's no way that would still update.
I agree with that a method .toPlainObject() would be really helpful.
For ex, if I have a schema like:
export const userSchema = {
name: 'User',
primaryKey: 'id',
properties: {
id: 'string',
user_id: 'string',
list_of_house_id: 'int[]',
}
}
and I want to copy this list_of_house_id to a javascript list: js_list_of_house_id. I tried Array.prototype.slice.call(list_of_house_id), but it is extremely slow, for just 2500 entries, it takes roughly 10 seconds to copy all the entries to js_list_of_house_id. I noticed that when I query the user from realm storage, the field list_of_house_id is a Proxy object, but there's no property in the Proxy which allows me to get the entire list directly.
I've been using the realmToPOJO() solution by @sampurcell93 until I tackle with an object that had an attribute which value is a byte array. Some lodash made the trick: _.assign({}, realmObject) :)
Whenever I try to run the realmToPOJO function, I get an error: Error opening default.realm: RangeError: Maximum call stack size exceeded
Any ideas? For now I'm creating the JSON by hand...
Whenever I try to run the realmToPOJO function, I get an error:
Error opening default.realm: RangeError: Maximum call stack size exceededAny ideas? For now I'm creating the JSON by hand...
@L4grange It sounds like you might have cycles in your JSON object e.g.
const child = {}
const parent = {}
parent['parentKey'] = child
child['childKey'] = parent
stringify keeps on following the keys and values until you exceed the stack.
Thanks @staufman !
I have linking objects, pointing back to the parents. Is that what is creating the loop? Can I exclude linking objects from the stringily functions? I only need the parent relationships for practicality in my code, not when printing my data.
Most helpful comment
In my testing, the recursive method works fine, but is extremely slow when there are nested objects, even when they're only one layer deep. I've had much better performance with this:
Performance for the average object increased by ~50%. All my objects were at most one level nested.