dresende / node-orm2

Object Relational Mapping
http://github.com/dresende/node-orm2
MIT License
3.07k stars 379 forks source link

Bad integration with EJS #827

Closed DimitarDechew closed 3 years ago

DimitarDechew commented 6 years ago

First of all I'm newbie in NodeJS and maybe my issue would be kinda useless. So firstly, I have 2 models with one to many relationship and it's working fine, but the problem is that the getModel function is async and I cannot display it in the EJS is there any way to get through this without writing async code? Another thing that I can't understand is: how can I convert my getter;setter class to JSON Object because I want to get all the data and create a form with dropdowns using the data in MySQL.

Best Regards, GhoSTBG

dxg commented 6 years ago
  1. Ideally you should not be calling async functions or database model functions inside your view - it would be better to have a function somewhere before this step which obtains all necessary data.
  2. ORM model instances behave like JSON objects:
    console.log(modelInstance)
    // prints weird get/set stuff
    console.log(JSON.stringify(modelInstance, null, 2))
    // prints the actual data

    The console thing makes it look confusing, but it behaves like a JSON object, so it should just work.

DimitarDechew commented 6 years ago

@dxg I really can't get this working. Here's my code:

let devices = [];
req.models.cluster.all(function(err, clusters) {
  clusters.forEach((cluster) => {
    cluster.getDevices((err, device) => {
      devices.push(JSON.stringify(device));
    })
    console.log(devices);
  });
});

console.log(devices) returns []

dxg commented 6 years ago

@GhoSTBG it's because cluster.getDevices is asynchronous and will return some time later. The console.log is printing before the call completes.

I recommend using a package like https://www.npmjs.com/package/async as then you can change the code to:


const async = require('async');
const _ = require('lodash');

function getDevices (req, cb) {
  req.models.cluster.all(function(err, clusters) {
    if (err) return cb(err);
    async.map(clusters, function (item, cb) {
      return item.getDevices(cb);
    }, function (err, devices) {
      if (err) return cb(err);

      console.log(JSON.stringify(devices, null, 2));

      cb(null, _.flatten(devices));
    });
  });
}

// somewhere else
getDevices(req, function (err, devices) {
  // we have devices, or an error
});

I highly recommend using async+await instead of callbacks, as then you can do something like this:

const _ = require('lodash');
const Promise = require('bluebird');

const getDevices = async function () {
  const clusters = await req.models.cluster.allAsync();
  const devices = _.flatten( await Promise.map(clusters, c => c.getDevicesAsync()) );

  console.log(JSON.stringify(devices, null, 2));

  return devices;
}
// Somewhere in your code:
const devices = await getDevices();