Help with promises and chaining database calls


#1

I have a data model that is pulled from a JSON API which has a number of nested objects. To handle this in SQLite, I have created a number of tables that use a key to chain relevant entries together.

For the sake of example:

{
  "people": {
    "ID": 104,
    "Name": "Geoff",
    "Country": "Australia",
    "Hobbies": [{
      "name": "cricket",
      "type": "sport"
    }, {
      "name": "painting",
      "type": "arts"
    }]
  }
}

When the hobbies are parsed, they are stored along with an additional property: ownerID (the ID of the root object).
In order to fetch and rebuild the objects from the SQLite DB however, I need to perform a number of sequential db calls.

e.g.

  1. Get people
  2. for each person in people: get hobbies where Person.ID = Hobbies.ownerID.
  3. Push hobbies to person object.
  4. Repeat for any additional nested properties.

My problem is that I within Ionic2 these DB calls use promises, which I can’t seem to chain correctly.

  getPeople() {

    return new Promise(function (resolve, reject) {

      let group = [];

      this.db.getPeople.then(people => {
        console.log('Getting people called');

        // For each person get their banner images etc.
        people.forEach(person => {

           //Get Hobbies
          this.db.getImagesForPerson(person.id).then(hobbies => {
            person.hobbies = hobbies;
          });

          group.push(speaker);
        });
      });

      if (group.length > 0) {
        resolve(group);
      } else {
        reject(error("Done Goofed"));
      }
    });
  }

This method is declared in a dedicated controller class, which has the following setup:

import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {DBHelper} from '../providers/db-helper'

@Injectable()
export class SpeakerController {
  static get parameters() {
    return [[Http], [DBHelper]];
  }

  constructor(http, db) {
    // inject the Http provider and set to this instance
    this.http = http;
    this.db = db;
  }

When the method is called however, I receive the following error: browser_adapter.ts:73 Error: Uncaught (in promise): TypeError: Cannot read property 'db' of undefined

Can anyone let me know where I’m going wrong, or point me in the right direction?


#2

Nevermind,

I think I resolved the issue by simply creating a new instance of DBHelper and passing it, rather than relying on the injection, as it seems it was being lost in the scope somehow. The methods are chaining well.

Thanks anyway.


#3

Just to alert you!

The code:

if (group.length > 0) { resolve(group); } else { reject(error("Done Goofed")); }

Group will be always length zero. Why? Because promises are async.

Will run something like this:

` return new Promise(function (resolve, reject) {

  let group = [];

  this.db.getPeople.then(people => {
    console.log('1');

    // For each person get their banner images etc.
    people.forEach(person => {

       //Get Hobbies
      this.db.getImagesForPerson(person.id).then(hobbies => {
    console.log('2');
        person.hobbies = hobbies;
      });

      group.push(speaker);
    });
  });

  if (group.length > 0) {
    console.log('3');
    resolve(group);
  } else {
    console.log('4');
    reject(error("Done Goofed"));
  }
});`

Output will be: 4,1,2


#4

Hi @mauricionarcizo, thanks for pointing this out. I actually moved it inside the getPeople() method.

My issue seems to stem from passing method calls that use ‘this’. Is there a recommendation as to how to avoid it? Do I explicitly declare the class each time? It just seems a bit strange?