how to use react-native realm - react-native

I started to use realm in my project and I have a question about retrieving the data. When I make a call to query all of the objects in my Subdivision model the return result includes the get/set methods. I must parse and stringify this before I am able to use it. I have read the docs and I do not see anything about this. Is this something that has to be done or am I missing something?
Model
class Subdivision extends Realm.Object { }
Subdivision.schema = {
name: 'Subdivision',
primaryKey: 'id',
properties: {
id: 'int',
subdivisionName: 'string',
latitude: 'float',
longitude: 'float',
status: 'string',
statusFlag: 'string',
marketId: 'int',
color: { type: 'int', optional: true },
colorStr: { type: 'string', optional: true }
}
};
Setting Subdivisions
_.each(response, (item) => {
Realm.write(() => {
Realm.create('Subdivision', item);
});
});
Getting Subdivisions
let result = Realm.objects('Subdivision');
let strRes = JSON.parse(JSON.stringify(result))

You shouldn't have to call JSON.stringify on result. Realm.objects returns a Results object which functions very similiarly to a JS Array: https://realm.io/docs/react-native/0.13.0/api/Realm.Results.html
You should be able to access each result using subscript indexing or other JS enumerations methods, ie result[0], or results.forEach((subidv) => {...}) etc.

Related

Computed not reactive?

I wrote this code to return a list of skills. If the user already has a specific skill, the list-item should be updated to active = false.
This is my initial code:
setup () {
const user = ref ({
id: null,
skills: []
});
const available_skills = ref ([
{value: 'css', label: 'CSS', active: true},
{value: 'html', label: 'HTML', active: true},
{value: 'php', label: 'PHP', active: true},
{value: 'python', label: 'Python', active: true},
{value: 'sql', label: 'SQL', active: true},
]);
const computed_skills = computed (() => {
let result = available_skills.value.map ((skill) => {
if (user.value.skills.map ((sk) => {
return sk.name;
}).includes (skill.label)) {
skill.active = false;
}
return skill;
});
return result;
})
return {
user, computed_skills
}
},
This works fine on the initial rendering. But if I remove a skill from the user doing
user.skills.splice(index, 1) the computed_skills are not being updated.
Why is that the case?
In JavaScript user or an object is a refence to the object which is the pointer itself will not change upon changing the underling properties hence the computed is not triggered
kid of like computed property for an array and if that array get pushed with new values, the pointer of the array does not change but the underling reference only changes.
Work around:
try and reassign user by shadowing the variable
The computed prop is actually being recomputed when you update user.skills, but the mapping of available_skills produces the same result, so there's no apparent change.
Assuming user.skills contains the full skill set from available_skills, the first computation sets all skill.active to false. When the user clicks the skill to remove it, the re-computation doesn't set skill.active again (there's no else clause).
let result = available_skills.value.map((skill) => {
if (
user.value.skills
.map((sk) => {
return sk.name;
})
.includes(skill.label)
) {
skill.active = false;
}
// ❌ no else to set `skill.active`
return skill;
});
However, your computed prop has a side effect of mutating the original data (i.e., in skill.active = false), which should be avoided. The mapping above should clone the original skill item, and insert a new active property:
const skills = user.value.skills.map(sk => sk.name);
let result = available_skills.value.map((skill) => {
return {
...skill,
active: skills.includes(skill.label)
}
});
demo
slice just returns a copy of the changed array, it doesn't change the original instance..hence computed property is not reactive
Try using below code
user.skills = user.skills.splice(index, 1);

Realm React Native: How remove element from object's nested array with some condition

I am new in React native and trying to integrate Realm as a client side DB.
I have 2 schemas:
export const CAR_SCHEMA = {
name: 'Car',
properties: {
color: 'string',
model: 'string',
}
};
export const PERSONS_SCHEMA = {
name: 'Person',
primaryKey: 'id',
properties: {
id: 'int',
firstName: 'string',
lastName: 'string'
cars: 'Cars[]'
}
};
My question basically means how to remove 'Car' from 'Person' where Car.model='Honda'? I couldn't find any documentation about deleting element from object's nested array.
Remove from array but keep item in Realm:
realm.write(() => {
let person = realm.objectForPrimaryKey('person', personId);
let carsOfPerson = person.cars;
var i = carsOfPerson.length - 1;
while(i >= 0) {
if(carsOfPerson[i].model == "Honda") {
carsOfPerson.splice(i, 1);
}
i--;
}
});
Remove from array by deleting item from Realm:
realm.write(() => {
let person = realm.objectForPrimaryKey('person', personId);
let carsOfPerson = person.cars;
let hondasOfPerson = carsOfPerson.filtered('model = "HONDA"')
realm.delete(hondasOfPerson)
});

Realm does not seems to working

I am trying to use realm in react-native android and I just wanted to test if it is working or not.
It seems to save data since it throws duplicated primaryKey error.
However, realm.objects('Person') does not return data but
Proxy
[[Handler]]
:
Object
[[Target]]
:
Results
[[IsRevoked]]
:
false
class Person {}
Person.schema = {
name: 'Person',
primaryKey: 'name',
properties: {
name: 'string',
age: {type: 'int', default: 0},
},
};
const realm = new Realm({schema: [Person],schemaVersion: 2});
// Write
realm.write(() => {
const savedPerson = realm.create('Person', {
name: 'Hal Incanden1za',
age: 17,
});
});
console.log(realm.objects('Person'))
The value you get from a realm.objects() call is not a normal array, so console.log may not be doing what you are expecting here. Try iterating through it instead.

Virtual "name" field?

I need to have the name field of a model be virtual, created by concatenating two real fields together. This name is just for display only. I've tried the virtual examples in the doc, no luck. Keystone 4 beta5.
var keystone = require('keystone')
_ = require('underscore');
var Types = keystone.Field.Types;
/**
* Foo Model
* ==================
*/
var Foo = new keystone.List('Foo', {
map: {name: 'fooname'},
track: true
});
Foo.add({
bar: { type: Types.Relationship, required: true, initial: true, label: 'Barref', ref: 'Bar', many: false },
order: { type: Types.Select, required: true, initial: true, label: 'Order', options: _.range(1,100) },
price: { type: Types.Money, format: '$0,0.00', label: 'Price', required: true, initial: true },
});
Foo.schema.virtual('fooname').get(function() {
return this.bar+ ' ' + this.order;
});
Foo.defaultColumns = 'fooname, bar, order, price';
Foo.register();
When I use this model definition, I don't see the virtual name in the defaultcolumns list. I want to make a virtual name so lookups are easier when this model is used as a relationship.
You don't need a virtual to do this. Keystone allows you to track and recalculate a field every time the document is saved. You can enable those options in order to create a function which concatenates these two values for you (either synchronously or asynchronously, your choice.)
One other thing I noticed is that bar is a Relationship, which means you will need to populate that relationship prior to getting any useful information out of it. That also means your value function will have to be asynchronous, which is as simple as passing a callback function as an argument to that function. Keystone does the rest. If you don't need any information from this bar, and you only need the _id (which the model always has), you can do without the keystone.list('Bar') function that I included.
http://keystonejs.com/docs/database/#fields-watching
The map object also refers to an option on your model, so you'll need a fooname attribute on your model in any scenario, though it gets calculated dynamically.
var keystone = require('keystone'),
_ = require('underscore');
var Types = keystone.Field.Types;
/**
* Foo Model
* ==================
*/
var Foo = new keystone.List('Foo', {
map: {name: 'fooname'},
track: true
});
Foo.add({
fooname: { type: Types.Text, watch: true, value: function (cb) {
// Use this if the "bar" that this document refers to has some information that is relevant to the naming of this document.
keystone.list('Bar').model.findOne({_id: this.bar.toString()}).exec(function (err, result) {
if (!err && result) {
// Result now has all the information of the current "bar"
// If you just need the _id of the "bar", and don't need any information from it, uncomment the code underneath the closure of the "keystone.list('Bar')" function.
return cb(this.bar.name + " " + this.order);
}
});
// Use this if you don't need anything out of the "bar" that this document refers to, just its _id.
// return cb(this.bar.toString() + " " + this.order);
} },
bar: { type: Types.Relationship, required: true, initial: true, label: 'Barref', ref: 'Bar', many: false },
order: { type: Types.Select, required: true, initial: true, label: 'Order', options: _.range(1,100) },
price: { type: Types.Money, format: '$0,0.00', label: 'Price', required: true, initial: true },
});
Foo.defaultColumns = 'fooname, bar, order, price';
Foo.register();
try this:
Foo.schema.pre('save', function (next) {
this.name = this.bar+ ' '+ this.order;
next();
});
Could you provide more information? What is currently working? How should it work?
Sample Code?
EDIT:
After creating the model Foo, you can access the Mongoose schema using the attribute Foo.schema. (Keystone Concepts)
This schema provides a pre-hook for all methods, which registered hooks. (Mongoose API Schema#pre)
One of those methods is save, which can be used like this:
Foo.schema.pre('save', function(next){
console.log('pre-save');
next();
});

Transform objects pointfree style with Ramda

Given the function below, how do I convert it to point-free style? Would be nice to use Ramda's prop and path and skip the data argument, but I just can't figure out the proper syntax.
const mapToOtherFormat = (data) => (
{
'Name': data.Name
'Email': data.User.Email,
'Foo': data.Foo[0].Bar
});
One option would be to make use of R.applySpec, which creates a new function that builds objects by applying the functions at each key of the supplied "spec" against the given arguments of the resulting function.
const mapToOtherFormat = R.applySpec({
Name: R.prop('Name'),
Email: R.path(['User', 'Email']),
Foo: R.path(['Foo', 0, 'Bar'])
})
const result = mapToOtherFormat({
Name: 'Bob',
User: { Email: 'bob#example.com' },
Foo: [{ Bar: 'moo' }, { Bar: 'baa' }]
})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
Here's my attempt:
const mapToOtherFormat = R.converge(
(...list) => R.pipe(...list)({}),
[
R.pipe(R.view(R.lensProp('Name')), R.set(R.lensProp('Name'))),
R.pipe(R.view(R.compose(R.lensProp('User'), R.lensProp('Email'))), R.set(R.lensProp('Email'))),
R.pipe(R.view(R.compose(R.lensProp('Foo'), R.lensIndex(0), R.lensProp('Bar'))), R.set(R.lensProp('Foo')))
]
)
const obj = {Name: 'name', User: {Email: 'email'}, Foo: [{Bar: 2}]}
mapToOtherFormat(obj)
Ramda console
[Edit]
We can make it completely point-free:
const mapToOtherFormat = R.converge(
R.pipe(R.pipe, R.flip(R.call)({})),
[
R.pipe(R.view(R.lensProp('Name')), R.set(R.lensProp('Name'))),
R.pipe(R.view(R.compose(R.lensProp('User'), R.lensProp('Email'))), R.set(R.lensProp('Email'))),
R.pipe(R.view(R.compose(R.lensProp('Foo'), R.lensIndex(0), R.lensProp('Bar'))), R.set(R.lensProp('Foo')))
]
)
Ramda console