How to store an Array of Arrays with Realm in React Native? - react-native

I want to store an array of arrays using Realm, but if I use type mixed it throws an error:
[Error: A mixed property cannot contain an array of values.]
This is my sample code:
export const ContentScheme = {
name: 'content',
primaryKey: 'elementId',
properties: {
elementId: 'string?',
currentTimeInfo: 'mixed',
}
}
Inserting Data:-
let data = {
elementId: '60d19799c0023702d41c1110',
currentTimeInfo:[["03.41", "03.29"], ["03.30", "05.14"], ["05.18", "00.00"]]
}

For my approach, I will create another schema CurrentTimeSchema and store it as array in ContentSchema.
Here is the solution.
export const ContentScheme = {
name: 'content',
primaryKey: 'elementId',
properties: {
elementId: 'string?',
currentTimeInfo: 'CurrentTime[]', <-- store CurrentTime in []
}
}
export const CurrentTimeSchema = {
name: 'CurrentTime',
embedded: true, <-- avoid creating new object of CurrentTime
properties: {
time1: 'string?', <-- rename these
time2: 'string?',
}
};

Related

react native redux toolkit how can I pass data to array?

How can I pass data to array (redux toolkit) ?
I tried this but not working.
I have an array of shippers:
const shipper = [
{
type: 'NORMAL',
item: {
id: 1,
name: 'SHIPPER1',
}
},
{
type: 'NORMAL',
item: {
id: 2,
name: 'SHIPPER2',
}
},
{
type: 'NORMAL',
item: {
id: 3,
name: 'SHIPPER3',
}
},
{
type: 'NORMAL',
item: {
id: 4,
name: 'SHIPPER4',
}
},
{
type: 'NORMAL',
item: {
id: 5,
name: 'SHIPPER5',
}
},
];
I want to add each item to the reducer array. Like this without redux.
setShippers(prevState => {
return [...prevState, shipper];
});
But I want it in Redux Toolkit:
slice/shipper.js
import { createSlice } from "#reduxjs/toolkit";
const createProductShipper = createSlice({
name: "createProductShipper",
initialState: {
shippers: []
},
reducers: {
AddProductShipper(state, action) {
state.shippers = [...state.shippers, action.payload];
},
}
});
export const { AddProductShipper } = createProductShipper.actions;
export default createProductShipper.reducer;
...
dispatch(AddProductShippers({id, shipper});
...
..................................................................................................................................................................................................................
I’m a bit confused about whether the shipper variable is an array or a single shipper — and I suspect that you are too.
Your “without redux” example would be the correct way to add a single shipper to the array. If shipper is an array then you’ll want to spread both prevState and shipper:
setShippers(prevState => [...prevState, …shipper]);
The same goes for the redux reducer.
But the way that you are calling the dispatch seems strange:
dispatch(AddProductShippers({id, shipper}));
This will dispatch an action whose payload has properties id and shipper. Is that what you want? What is the id property: the product id or the shipper id?
Assuming that the product id is irrelevant (it appears nowhere in your slice) and that you want to add an array of shippers, your code might look something like this:
dispatch(AddProductShippers(arrayOfShippers));
AddProductShipper(state, action) {
state.shippers = [...state.shippers, …action.payload];
}
Or
AddProductShipper(state, action) {
state.shippers.push(…action.payload);
}

I get different result from Graphql playground and front-end

I am using graphql and Vue.js and apollo
Here is my DateBank
const sensorsdb = [
{
name: "sensor 1",
id: "s-1",
timestamp: 1582021371,
value: 100
},
{
name: "sensor 1",
id: "s-1",
timestamp: 1579451703,
value: 150
},
{
name: "sensor 2-1",
id: "s-2-1",
timestamp: 1582021371,
value: 200
},
{
name: "sensor 2-2",
id: "s-2-2",
timestamp: 1579451703,
value: 350
},
{
name: "sensor 2-2",
id: "s-2-2",
timestamp: 1582021371,
value: 300
},
{
name: "sensor 3",
id: "s-3",
timestamp: 1582021371,
value: 400
},];
I want to get all objects according to object id. sensorId is an array. because I want to get multiple objects with multiple ids.
The following is my API function to get object.
async getDataById({ sensorId }) {
let sensorsData = [];
for (let i = 0; i < sensorId.length; i++) {
let sensorData = this.sensorDataStore.sensors.filter(sensor => sensor.id === sensorId[i]);
sensorsData = sensorsData.concat(sensorData);
}
return sensorsData;
}
In Front-end, gql file is following:
query sensorData($id: [String]){
sensorData(id: $id){
name
id
value
timestamp
}}
and with my apollo query code in vue.js, in this case selectedSensorId is ["s-2-1", "s-2-2"]
<ApolloQuery :query="require('../graphql/sensorDataById.gql')" :variables="{ id: selectedSensorId }">
<template v-slot="{ result: { loading, error, data } }">
<b-loading :is-full-page=true :active.sync=loading :can-cancel="false"/>
<div v-if="error">
<no-data-error />
</div>
<div v-if="data">
{{ data }}
<bar-chart-view :sensorInfo="data.sensorData"/>
</div>
</template>
</ApolloQuery>
But I got the following different result:
Graphql playground which has correct result
The front-end result with duplicated sensor-s-2
Apollo Client normalizes results according to the id and __typename fields as described in the docs. If an array returns multiple items with the same id, by default they will share the same cache key, which means what's returned by the client will be the same object.
You should provide a custom dataIdFromObject function to your InMemoryCache constructor that accommodates your specific use case. Something like:
const dataIdFromObject = object => {
switch (object.__typename) {
case 'SensorDataPoint': return `SensorDataPoint:${object.id}:{value}`;
default: return defaultDataIdFromObject(object);
}
}
Note that if you use the same type elsewhere, you may experience issues with the cache updated correctly after mutations because we are now keying off both the value and id. You might want to consider a different approach to your schema where the ids are actually unique :
type SensorDataPoint {
id: ID!
sensorId: ID!
sensorName: String!
value: Int!
timestamp: Int!
}
or even better
type SensorDataPoint {
id: ID!
value: Int!
timestamp: Int!
sensor: Sensor!
}
type Sensor {
id: ID!
name: String!
}
I know it its been a while but what Daniel Rearden mentioned above, I included the { addTypename: false } as options for InMemoryCache
const client = new ApolloClient({
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.forEach(({ message, extensions }) => {
console.log(`[GraphQL error]: Message: ${message}, Code: ${extensions?.code}`)
})
if (networkError) {
console.log(`[Network error] ->: ${networkError}`)
Toast.show('Connection Error', {
position: Toast.positions.TOP,
type: 'danger',
duration: 3000,
})
}
}),
authMiddleware,
link,
]),
cache: new InMemoryCache({ addTypename: false }),
});

Undefined is not an object using react native realm

I want to build an application using react native and implement realm. It is meant to have some playlists and songs, and the songs should be able to be added to the playlists.
Playlist:
export class Playlist {
public id: number;
public name: string;
public color: string;
public songs: Song[];
constructor(id: number, name: string, color: string, songs: Song[]) {
this.id = id;
this.name = name;
this.color = color;
this.songs = songs;
}
static schema: Realm.ObjectSchema = {
name: 'Playlist',
primaryKey: 'id',
properties: {
id: 'int',
name: 'string',
color: 'string',
songs: 'Song[]',
},
};
}
Song:
export class Song {
public id: number;
public title: string;
public artist: string;
constructor(id: number, title: string, artist: string) {
this.id = id;
this.title = title;
this.artist = artist;
}
static schema: Realm.ObjectSchema = {
name: 'Song',
primaryKey: 'id',
properties: {
id: 'int',
title: 'string',
artist: 'string',
},
};
}
Realm:
const initData = () => {
const songs = [
new Song(0, 'Avicii', 'Heaven'),
// some songs
];
const playlists = [
new Playlist(0, 'Favorite Songs', 'purple', []),
// some playlists
];
songs.forEach(song => {
Song.insertSong(song);
});
playlists.forEach(playlist => {
Playlist.insertPlaylist(playlist);
});
};
const databaseOptions = {
path: 'playlists.realm',
schema: [Playlist.schema, Song.schema],
};
let realmInstance: Realm | null;
const getRealm = (): Realm => {
if (realmInstance == null) {
realmInstance = new Realm(databaseOptions);
initData();
}
return realmInstance!;
};
export default getRealm;
I always get the error:
TypeError: undefined is not an object (evaluating '_playlist.Playlist.schema')
And I can't figure out why. If you need more code, just tell me.
I am new to react native and JavaScript and TypeScript. I am used to developing Android apps using Java, so maybe I did some dumb mistakes, I don't know.
You are not using your real instance in initData, you need to use realm.write like in the below example. I think my little piece of code should works update me what u got(its better to use Realm async than sync as you want)
const PersonSchema = {
name: 'Person',
properties: {
// The following property definitions are equivalent
cars: {type: 'list', objectType: 'Car'},
vans: 'Car[]'
}
}
let carList = person.cars;
// Add new cars to the list
realm.write(() => {
carList.push({make: 'Honda', model: 'Accord', miles: 100});
carList.push({make: 'Toyota', model: 'Prius', miles: 200});
});
let secondCar = carList[1].model; // access using an array index
In your case
Realm.open({schema: [Song, PlayList]})
.then(realm => {
// ...use the realm instance here
try {
realm.write(() => {
const songs = [
realm.create('Song',{title: 'Avicii', artist: 'Heaven'}),
];
const playlists = [
realm.create('Playlist',{name: 'Favorite Songs', color: 'purple', songs: []}),
// some playlists
];
playlists.forEach(playlist => {
for (const song of songs){
playlist.songs.push(song);
}
});
});
} catch (e) {
console.log("Error on creation");
}
})
.catch(error => {
// Handle the error here if something went wrong
});

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.