Pushing to list in realm - react-native

These are my realm objects. I have Hole and Round. I am trying to populate my round with 18 hole objects in a single write but I've been stuck on this for the past few hours and I can't seem to understand where I'm going wrong.
class Hole extends Realm.Object {}
Hole.schema = {
name: 'Hole',
primaryKey: 'id',
properties: {
id: 'int',
fullStroke: 'int',
halfStroke: 'int',
puts: 'int',
firstPutDistance: 'int',
penalties: 'int',
fairway: 'string'
},
};
class Round extends Realm.Object {}
Round.schema = {
name: 'Round',
primaryKey: 'id',
properties: {
id: 'string',
done: 'string',
holes: {type: 'list', objectType: 'Hole'}
},
};
Here is my function that is attempting to push every hole into the hole property of Round. Any help would be greatly appreciated.
exportRound = () => {
let holesObjects = realm.objects('Hole')
if(holesObjects.length < 9){
alert('Enter stats for at least 9 holes please')
}
else{
var sortedHoles = holesObjects.sorted('id')
currentRound = realm.objects('Round').filtered('done == "no"')
for(var i = 1; i < holesObjects.length; i++){
console.log(holesObjects.filtered('id == i'))
realm.write(()=> currentRound.holes.push(holesObjects.filtered('id == {i}')) )
}
}
}

What's error are you facing?
I found some mistake in your code.
The type of currentRound object is Results. It is not Round object until you retrieve each element. So it doesn't have holes property. You should retrieve the element contained by Results, like the following:
var currentRound = realm.objects('Round').filtered('done == "no"')[0]
String interpolation should be `id == ${i}` (Use backtick and ${}). So your query should be:
holesObjects.filtered(`id == ${i}`)
holesObjects.filtered(`id == ${i}`) returns also Results object. You should retrieve an element first.
realm.write(()=> currentRound.holes.push(holesObjects.filtered(`id == ${i}`)[0]))
The whole code that I edited is the following:
exportRound = () => {
let holesObjects = realm.objects('Hole')
console.log(holesObjects);
if(holesObjects.length < 9){
alert('Enter stats for at least 9 holes please')
}
else{
var sortedHoles = holesObjects.sorted('id')
var currentRound = realm.objects('Round').filtered('done == "no"')[0]
console.log(currentRound)
for(var i = 1; i < holesObjects.length; i++){
console.log(holesObjects.filtered(`id == ${i}`))
realm.write(()=> currentRound.holes.push(holesObjects.filtered(`id == ${i}`)[0]))
}
}
}

Related

Row Span AutoGrouping and Bug

I've created a plnkr to auto-group row-spans the way you would really expect it to work out of the box IMHO.
Anyhow... doing this surfaces an apparent bug... the rowSpan is not consistently applied to the grid.. if you scroll up and down, it sometimes applies, and sometimes does not.
In the screenshot below... you can see 'Aaron Peirsol' is spanning... but if I scroll up and down it might not span on him... not consistent.
Here 'Aaron Peirsol' is no longer spanning all 3 rows -- all I did was scroll up and back down
See this Sample
https://plnkr.co/edit/UxOcCL1SEY4tScn2?open=app%2Fapp.component.ts
Here I've added columndefs for the grouping
{
field: 'athlete',
rowSpan: params => params.data.groupCount,
cellClassRules: {
'cell-span': "data.isFirst && data.groupCount>1",
},
width: 200,
},
{field:'groupCount', width: 20}, /* included for debugging */
{field:'isFirst', width: 20}, /* included for debugging */
And here I'm doing the auto-grouping code:
onGridReady(params: GridReadyEvent) {
this.http
.get<any[]>('https://www.ag-grid.com/example-assets/olympic-winners.json')
.subscribe((data) => {
let groupKey = 'athlete';
let sorted = data.sort((a,b) => (a[groupKey] > b[groupKey]) ? 1 :
((b[groupKey] > a[groupKey]) ? -1 : 0));
let filtered = sorted.filter(x => {
return x[groupKey] < 'Albert' && x[groupKey];
});
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
let keyValue = x[key];
if (rv[keyValue] === undefined)
{
rv[keyValue] = 0;
}
if (keyValue) {
rv[keyValue] ++;
}
return rv;
}, {});
};
let grouped = groupBy(filtered, groupKey);
let prev = '';
for (let i=0; i<filtered.length; i++)
{
let keyValue = filtered[i][groupKey];
filtered[i]['groupCount'] = grouped[keyValue];
if (keyValue == prev)
{
filtered[i]['isFirst'] = false;
}
else
{
filtered[i]['isFirst'] = true;
}
prev = keyValue;
}
this.rowData = filtered});
}
OK, found the issue...
rowSpan function must only return a span count for the first row of the span...
every other row it must return 1
I've updated the plunker
public columnDefs: ColDef[] = [
{
field: 'athlete',
rowSpan: params => params.data.groupRowCount == 1 ? params.data.groupCount: 1, //THIS IS CRUCIAL.. only return count for first row
cellClassRules: {
'cell-span': "data.groupRowCount==1 && data.groupCount>1",
},
width: 200,
},

How group and count elements by lodash

has data
items = {
0: {id:1,name:'foo'},
1: {id:2,name:'bar'},
2: {id:1,name:'foo'}
};
I wont get counted elements like this
result = {
0: {id:1,name:'foo', count:2},
1: {id:2,name:'bar', count:1}
};
lodash has function _.countBy(items, 'name') it's got {'foo': 2, 'bar':1}, i need id too.
If pure JS approach is acceptable, you can try something like this:
Logiic:
Loop over array and copy the object and add a property count and set it to 0.
Now on every iteration update this count variable.
Using above 2 steps, create a hashMap.
Now loop over hashMap again and convert it back to array.
var items = [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}, {
id: 1,
name: 'foo'
}
];
var temp = items.reduce(function(p,c){
var defaultValue = {
name: c.name,
id: c.id,
count: 0
};
p[c.name] = p[c.name] || defaultValue
p[c.name].count++;
return p;
}, {});
var result = [];
for( var k in temp ){
result.push(temp[k]);
}
console.log(result)

Improve the speed of a realm query in react-native?

I have something like the following code in my react native app to set up mock/test data for performance tests.
realm.write(() => {
const max = 120;
for(let x=1; x<=max; x++)
{
realm.create('Product', {productId:x});
}
for(let x=1; x<=max; x++)
{
for(let y=x; y<=max; y++)
{
for(let z=y; z<=max; z++)
{
realm.create('Compatibility', {
result: 'Y '+x+' '+y+' '+z,
products: [
realm.objects('Product').filtered('productId = '+x)[0],
realm.objects('Product').filtered('productId = '+y)[0],
realm.objects('Product').filtered('productId = '+z)[0]
]
});
}
}
}
});
class Product {}
Product.schema = {
name: 'Product',
primaryKey:'productId',
properties: {
productId:'int'
}
};
class Compatibility {}
Compatibility.schema = {
name: 'Compatibility',
properties: {
result: {type: 'string'},
products: {type: 'list',objectType:'Product'},
}
};
This means the Products object has 120 records and the Compatibility object has 1.7 million records.
When I run the query realm.objects('Compatibility').filtered(products.productId = 3 AND products.productId = 25 AND products.productId = 97), it takes about 15 seconds to run on my old HTC Desire 510 and my Huawei Nova Plus. This is too slow.
Is there a way to improve the speed of the query? For example, can you index the columns or something?
First of all there is indexing in realm and primaryKeys are indexed already. So indexing in this scenario won't help you. But I think I have an idea of how you could get faster the process.
At the last for loop you are doing 3 queries. 2 of them happens unnecessarily I think since x and y values going to be same for 120 z values. If you implement something like the code below, it might help a little bit with the performance I think.
let productX;
let productY;
let productZ;
for (let x = 1; x <= max; x++)
{
productX = realm.objects('Product').filtered('productId = ' + x)[0];
for (let y = x; y <= max; y++)
{
productY = realm.objects('Product').filtered('productId = ' + y)[0];
for (let z = y; z <= max; z++)
{
productZ = realm.objects('Product').filtered('productId = ' + z)[0];
realm.create('Compatibility',
{
result: 'Y ' + x + ' ' + y + ' ' + z,
products: [ productX, productY, productZ]
});
}
}
}
A second though;
This might be a really bad idea and can be a terrible practice but I'm going to give as a thought practice.
If you are always doing query with 3 different productIds, you can create a string with all tree in a single property and query only that. This way you can use indexing.
Example
class Compatibility {}
Compatibility.schema = {
name: 'Compatibility',
properties: {
result: {type: 'string'},
productQueryHelper: { type: 'string', indexed: true }
products: {type: 'list',objectType:'Product'},
}
};
realm.create('Compatibility',
{
result: 'Y ' + x + ' ' + y + ' ' + z,
productQueryHelper: `${x}&${y}&${z}` // you can use any other separator that isn't possible to be in productId
products: [
realm.objects('Product').filtered('productId = ' + x)[0],
realm.objects('Product').filtered('productId = ' + y)[0],
realm.objects('Product').filtered('productId = ' + z)[0]
]
});
realm.objects('Compatibility').filtered('productQueryHelper = "3&25&97"')
Try to set your primary keys as indexed.
Btw I've never had problems with performance using Realm.
Nowadays I'm using Realm in a scenario to manage my notifications. I have a lot of queries running at some time and this never hurt the performance.
class Product {}
Product.schema = {
name: 'Product',
primaryKey:'productId',
properties: {
productId: { type: 'int', indexed: true }
}
};
class Compatibility {}
Compatibility.schema = {
name: 'Compatibility',
properties: {
result: {type: 'string'},
products: {type: 'list',objectType:'Product'},
}
};

Realm very slow for adding/updating records

I have this react native application which imports the phone contacts to database. I have about 100 contacts in my phone and it's taking ages...like 1 import per second which is. I'm sure, a mistake I'm doing somewhere even though the code is simple.
realm.write(() => {
for (let i = 0, len = contacts.length; i < len; i++) {
Contact.saveOrUpdate(contacts[i].name, contacts[i].recordID, contacts[i].phoneNumbers);
}
});
saveOrUpdate method:
class Contact {
static saveOrUpdate(name, recordId, phones) {
const save = () => {
let c;
try {
// try an update first
c = realm.create('Contact', {
name: name.toString(),
recordID: recordId.toString()
}, true);
} catch (e) {
// if that fails, create a new contact
console.log("Created " + recordId);
c = realm.create('Contact', {
name: name.toString(),
recordID: recordId.toString()
});
}
c.phones = [];
for (let i = 0, len = phones.length; i < len; i++) {
c.phones.push({
number: phones[i].toString()
});
}
// now run an update with the phone numbers
return realm.create('Contact', c, true);
};
return save();
}
}
My realm schema:
const PhoneNumberSchema = {
name: 'PhoneNumber',
properties: {
number: 'string'
}
};
const ContactSchema = {
name: 'Contact',
primaryKey: 'recordID',
properties: {
recordID: 'string',
name: {
type: 'string',
indexed: true
},
phones: {
type: 'list',
objectType: 'PhoneNumber'
}
}
};
Can anyone spot what am I doing wrong here that it takes so long for 100 contacts to be stored?

Pivot data dynamically for google line chart

I want to display "population" of various countries through the years in the same line chart. The data displayed is based on selections from a multi-select dropdown "Countries". Underlying Data Table has 3 columns:
Year, Country, Population
2012,countryA,33
2013,countryA,35
2014,countryA,40
2012,countryB,65
2013,countryB,70
2014,countryB,75
2012,countryC,15
2013,countryC,20
2014,countryC,25
I am trying to create a pivoted Data View from the underlying Data Table
The code I am using is:
function drawLineChart() {
var arr = $('#country').val();
var lineChartJson = $.ajax({
url: "../json/lineChart.json",
dataType: "json",
async: false
}).responseText;
var lineChartData = new google.visualization.DataTable(lineChartJson);
var view = new google.visualization.DataView(lineChartData);
var viewCols = [0];
for(var i = 0; i < arr.length; i++) {
var viewCols1 = [{
type: 'number',
label: arr[i],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[i]) ? dt.getValue(row, 2) : null;
}
}];
viewCols = viewCols.concat(viewCols1);
}
view.setColumns(viewCols);
var aggCols = [{
column: 1,
type: 'number',
label: view.getColumnLabel(1),
aggregation: google.visualization.data.sum
}];
for(var i = 2; i < 4; i++) {
var aggCols1 = [{
column: i,
type: 'number',
label: view.getColumnLabel(i),
aggregation: google.visualization.data.sum
}];
aggCols = aggCols.concat(aggCols1);
}
var pivotedData = google.visualization.data.group(view, [0], aggCols);
But this does not seem to work as expected and I just get 1 Line in the chart with values for all countries added up (although I can see the legend for 3 countries)
On the other hand if I set my View columns as below, it works as expected.
view.setColumns([0, {
type: 'number',
label: arr[0],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[0]) ? dt.getValue(row, 2) : null;
}
}, {
type: 'number',
label: arr[1],
calc: function (dt, row) {
// return values of C only for the rows where B = "bar"
return (dt.getValue(row, 1) == arr[1]) ? dt.getValue(row, 2) : null;
}
}, {
type: 'number',
label: arr[2],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[2]) ? dt.getValue(row, 2) : null;
}
}]);
What is going wrong in the loop? Is something wrong with "concat" in the loop where I am creating View Columns? I also saw the viewCols array by using console.log and it seems to have the right elements
I was trying to follow the below post:
Creating pivoted DataView from existing google charts DataTable object
the problem has to do with scope
arr[i] is undefined within calc: function (dt, row)
here is another way to pivot the data...
google.charts.load('current', {
callback: function () {
var arr = [
'countryA',
'countryB',
'countryC'
];
var lineChartData = google.visualization.arrayToDataTable([
['Year', 'Country', 'Population'],
[2012,'countryA',33],
[2013,'countryA',35],
[2014,'countryA',40],
[2012,'countryB',65],
[2013,'countryB',70],
[2014,'countryB',75],
[2012,'countryC',15],
[2013,'countryC',20],
[2014,'countryC',25]
]);
// sort by year
lineChartData.sort([{column: 0}]);
// get unique countries
var countryGroup = google.visualization.data.group(
lineChartData,
[1]
);
// build country data table
var countryData = new google.visualization.DataTable({
cols: [
{label: 'Year', type: 'number'},
]
});
// add column for each country
for (var i = 0; i < countryGroup.getNumberOfRows(); i++) {
countryData.addColumn(
{label: countryGroup.getValue(i, 0), type: 'number'}
);
}
// add row for each year / country
var rowYear;
var rowIndex;
for (var i = 0; i < lineChartData.getNumberOfRows(); i++) {
if (rowYear !== lineChartData.getValue(i, 0)) {
rowYear = lineChartData.getValue(i, 0);
rowIndex = countryData.addRow();
countryData.setValue(rowIndex, 0, rowYear);
}
for (var x = 1; x < countryData.getNumberOfColumns(); x++) {
if (countryData.getColumnLabel(x) === lineChartData.getValue(i, 1)) {
countryData.setValue(rowIndex, x, lineChartData.getValue(i, 2));
}
}
}
// draw agg table
new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'table-div',
dataTable: countryData
}).draw();
// draw line chart
new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart-div',
dataTable: countryData
}).draw();
},
packages: ['corechart', 'table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="table-div"></div>
<div id="chart-div"></div>
I could figure out the problem with my code above.
"calc" is the callback function in loop. So only last value of loop variable "i" is visible within the loop.
Putting a wrapper function fixes it:
for(var i = 0; i <= arr.length; i++)(function(i) {
var viewCols1 = [{
type: 'number',
label: arr[i],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[i]) ? dt.getValue(row, 2) : null;
}
}];
viewCols = viewCols.concat(viewCols1);
})(i);