Is there a way to present One2Many Relation in correct way in realm? - react-native

I have a very simple schema structure in my mobile app:
export const DepositSchema = {
name: "Deposit",
properties: {
uuid: "string",
payments: "Payment[]",
},
primaryKey: "uuid",
};
export const PaymentSchema = {
name: Instance.Payment,
properties: {
payment_amount: "string",
payment_method: "string",
deposit: {
type: "linkingObjects",
objectType: "Deposit",
property: "payments",
},
},
primaryKey: "uuid",
};
So means that every deposit can have zero, one or few payments (it can be paid partially), but one payment should be assigned only to one deposit
I put Payment objects to Realm database as below:
database.manager.write(() => {
if (payment.deposit_uuid) {
deposit = database.manager.objectForPrimaryKey("Deposit", payment.deposit_uuid);
}
const createdDbPayment = database.manager.create(
Instance.Payment,
{
...payment,
status: STATUS_TO_IGNORE,
},
Realm.UpdateMode.Modified,
);
if (deposit && createdDbPayment && deposit.payments.filtered("uuid == $0", payment.uuid).length == 0) {
deposit.payments.push(createdDbPayment);
}
});
Meanwhile, when i try to log payment object gotten from Realm Database it looks that instead of one deposit assigned to this payment, I got array of deposits. (ofc with only one object but it's very annoying)
The question is: Is there a way to connect this schema to present One2Many (not many2many) relationship?
I would like to achieve:
payment.deposit.uuid instead of payment.deposit[0]?.uuidThanks for help

I would like to achieve: payment.deposit.uuid instead of
payment.deposit[0]?.uuid
Whenever LinkingObjects are used, they allow "automatic" navigation back to the parent object - however, they also create a many-many relationship by their nature.
That's why it's LinkingObjects (plural) not LinkingObject.
If there is only ever one to link back to, then your code will work with the index 0 being required to reference to the first element
payment.deposit[0]?.uuid
The benefit of LinkingObjects is the backlink is created for you (it's more of a calculated property than a managed property). On the other hand it's not exactly what you want.
So you'll need to create the backlink manually - and in some cases it makes more sense but you loose the 'automatic' relationship. Using pseudo-code
export const DepositSchema = {
name: "Deposit",
properties: {
payments: "Payment[]"
export const PaymentSchema = {
name: Payment,
properties: {
parent_deposit: "Deposit"
I would suggest adding a "addPayment" function to add a payment to the Deposit. When a payment is passed to the Deposit property, the parent Deposit will add its reference to the payment and then add it to the Payments List.
That will create a forward relationship from Deposits to multiple Payments and then a single backward relationship from Payment back to its parent Deposit.
Then the graph can be transversed in both directions.

Related

Is there an easier way of updating nested arrays in react-native (react-redux)?

I am trying to update an array inside of my array (nested array) with react-redux. I found a solution to how to do this but is there any easier way of doing this rather than passing multiple parameter to the action.
[types.HISTORY_UPDATE](state, action){
return {
...state,
budgets: [
...state.budgets.slice(0,action.id),
{
key: action.key,
id: action.idd,
name: action.name,
budgetType: action.budgetType,
startDate: action.startDate,
currency: action.currency,
amount: action.amount,
amountLeft: action.amountLeft,
rollOver: action.rollOver,
color: action.color,
iconName: action.iconName,
history: [
...state.budgets[action.id].history.slice(0,action.histId),
{
note: action.note,
amount: action.amount,
type: action.type,
date: action.date,
fullDate: action.fullDate,
hours: action.hours,
min: action.min,
month: action.month,
year: action.year
},
...state.budgets[action.id].history.slice(action.histId+1)
]
},
...state.budgets.slice(action.id+1)
]
}
},
and the action goes like this
export function updateHistory(id,key,idd,name,budgetType,startDate,currency,amount,amountLeft,rollOver,color,iconName,histId,........){
I don't want to spend time with passing multiple parameter like this while using react-redux and also while I tried to run my application on my phone sometimes it really slows the application. Is it because of the example above?
I would be really appreciated If you guys come up with a solution.
I typically do not store arrays in redux, since updating a single element really is a burden as you noticed. If the objects you have inside your array all have a unique id, you can easily convert that array to an object of objects. As key for each object you take that id.
const convertToObject = (array) => {
let items = {};
array.map((item) => {
items[item.id] = item;
});
return items;
};
In your action you simply just pass the item you want to update as payload, and you can update the redux store very easily. In this example below I am just updating the budgets object, but the same logic applies when you assign a history object to each budget.
[types.BUDGET_UPDATE](state, action){
const item = action.payload;
return {
...state,
budgets: {
...state.budgets,
[item.id]: item
}
}
}
And if you want an array somewhere in your component code, you just convert the redux store object back to an array:
const array = Object.values(someReduxStoreObject);

Can VueX's store also emit events to components?

I have the following component tree:
App
List
ItemDetails
Widget1
...
the List component has a filters form, those are applied on button press
Widget1 has a button which applies another filter (by id) to the list, applying that one removes filters from the filter form and vice versa
the list is also live-updated via polling (later will be via WebSockets), so I have to separate v-model of the filter fields in List and the actually applied filters (those are in the store)
Currently, I've put the following state to the VueX store:
state: {
filters: {
// these come from the List's filter panel
result: '',
name: '',
date: '',
// this one comes from Widget1
id: '',
},
pagination: {
perPage: 10,
page: 0,
total: 0,
},
items: [],
selectedItem: null,
},
and both filters from the List and from the button in Widget1 are applied via dispatching the following action to the store:
applyFilters ({ state, commit, dispatch }, filters) {
if(filters.id) {
for(let filterName in state.filters)
if(filterName !== 'id')
filters[filterName] = '';
} else {
filters.id = '';
}
commit('setFilters', filters);
commit('setPage', 0);
dispatch('loadExaminations');
},
But here's the problem: the List component has its model of filter fields (on press of the button those are gathered and applyFilters is dispatched). This works well except when the id filter (from Widget1) is applied, the filter fields in the List component are not emptied.
One obvious option to handle this is to move the model of those filter fields to the store as well. That doesn't look that nice since for each field (that uses v-model) I have to create a computed (in the List component) and write a setter and a getter from the store. It seems nicer to send an event from applyFilters to List saying "empty the filter fields", but I'm not sure if VueX can do this. Is this possible? Or should I stick with the "move filter fields' model to the store" plan? Or do you know a nice alternative? I'm aware of the event bus concept, but that one uses Vue instance which shouldn't be used in store, I guess.
You can listen to vuex's actions by using subscribeAction.
// List.vue
mounted() {
this.$store.subscribeAction({
before: (action, state) => {
if (action.type === "applyFilters" && action.payload.id) {
this.emptyComponentFields();
}
},
after: (action, state) => {}
});
}
CodeSandbox.

In KeystoneJS, how can I make all values initially selected in a Relationship field using many: true?

I am using KeystoneJS. I have a relationship field in my Post model that references another model called Device. I am using many: true to allow users to select multiple items from the Device model.
Is there a way to have them all initially selected when creating a Post?
Right now my relationship field looks like this:
availableDevices: {
type: Types.Relationship,
ref: 'Device',
many: true
}
In your model definition, you can add pre-processing steps to populate fields that you'd like to have a default value in the relationship. I haven't done this with a many relationship, but I have done it with a relationship like this:
Report.schema.pre('save', function (next) {
this.wasNew = this.isNew;
if (!this.employee) {
this.employee = this.createdBy;
}
if (!this.timeEnteredTheHomeStr) {
if(!this.timeEnteredTheHome) {
this.timeEnteredTheHome = Date.now
}
this.timeEnteredTheHomeStr = String(this.timeEnteredTheHome);
}
next();
});
When someone creates a new report object, the employee field is automatically set to the user object referenced in the createdBy field.

How to handle reference in mobx?

For example I have Payments and have User. It's Many-to-one relationship. But I don't want to have Payments as nested properties of User.
In redux I would live an ID.
//redux
const state = {
users = [{
id: 232,
payments: [123]
}]
payments: [{
id: 123,
user: 232
}]
}
or something like this. What's the way to works with references in mobx?
I would like to use links so I can:
user.payment['doSomething']
The great thing with mobx is what you can store links in observable. All you need is init them.
const user = new User
const payment = new Payment
user.payment = payment
payment.user = user
Now you can do user.payment.value = 'newVal'
Just make sure property payment inside user and property user inside payment are #observable

Sencha touch 2 error, identifier generation strategy for the model does not ensure unique id's, while working with a store

In Sencha touch, I have defined a store:
Ext.define('TestApp.store.TokenStore', {
extend: 'Ext.data.Store',
config: {
model: 'TestApp.model.TokenModel',
autoLoad: true,
autoSync: true,
proxy: {
type: 'localstorage',
// The store's ID enables us to eference the store by the following ID.
// The unique ID of the Store will be the ID field of the Model.
id: 'TokenStore'
}
}
});
And a model for this store:
Ext.define('TestApp.model.TokenModel', {
extend: 'Ext.data.Model',
config:{
fields: [
{name: 'id', type: 'int' },
{name:'token',type:'string'}
]
}
});
Now, inside the launch function of my App, I do the following:
// Get the store
var tokenStore = Ext.getStore('TokenStore');
// Add a token to the store
tokenStore.add({'token': 1234});
// Retrieve that token back:
var token = tokenStore.getAt(0).get('token');
Everything works, I see the token's value in the console, but I get the following warning:
[WARN][Ext.data.Batch#runOperation] Your identifier generation strategy for the model does not ensure unique id's. Please use the UUID strategy, or implement your own identifier strategy with the flag isUnique.
What am I doing wrong?
Add this inside your config on the model:
identifier: {
type: 'uuid'
},
Sencha Touch requires each record across all classes to have a identifier. Basically, that's a class that assigns a string to each record. There's javascript classes in the touch source that generate these. Those classes must declare themselves either unique or not. uuid is the best to use that's included in sencha touch and declares itself as unique (with good reason if you take a look at the math it does based on timestamps!)
The reason you need unique identifiers is so that records are not mixed up with each other, especially when it comes to DOM interactions or saving/loading them via a proxy.
This will get rid of the warning and subsequent problems loading/saving, which will otherwise crop up after a number of saves/retrieves on the same store (the store will get eventually corrupted)
identifier: {
type: 'uuid',
isUnique : true
},
Tested in Chrome