2

I'm trying to get data from a document in RethinkDB in NodeJS and pass the result into a variable I wish to use in a template file, but it is always undefined when I try to print the data variable like #{data} (I'm using pug/jade) because it's an asynch call (i think).

'use strict';

var r = require('rethinkdb');

module.exports = function IndexModel() {
    data: {
        r.connect({host: '127.0.0.1', port: 28015}, function(err, conn) {
            r.db('mydb').table('mytable').run(conn).then(function(cursor) {
                cursor.toArray(function(err, result) {
                    if (err) throw err;
                    return JSON.stringify(result, null, 2);
                });
            });
        });
    }
};

I figured it must be because nodejs want it to be an object, so I tried to parse it like JSON.parse(JSON.stringify(result, null, 2)) but that throws the same error.

When I do console.log(JSON.stringify(result, null, 2)) it prints this after the error.

[
  {
    "id": "307ad5e9-a0db-461b-a564-081d73f9b34f",
    "title": "hello"
  }
]

This is the exact error if its needed:

Cannot read property 'length' of undefined
    at eval (eval at wrap (C:\Users\Me\Project\node_modules\pug-runtime\wrap.js:6:10), <anonymous>:248:32)
    at eval (eval at wrap (C:\Users\Me\Project\node_modules\pug-runtime\wrap.js:6:10), <anonymous>:379:4)
    at template (eval at wrap (C:\Users\Me\Project\node_modules\pug-runtime\wrap.js:6:10), <anonymous>:389:211)
    at Object.exports.renderFile (C:\Users\Me\Project\node_modules\pug\lib\index.js:427:38)
    at Object.exports.renderFile (C:\Users\Me\Project\node_modules\pug\lib\index.js:417:21)
    at View.exports.__express [as engine] (C:\Users\Me\Project\node_modules\pug\lib\index.js:464:11)
    at C:\Users\Me\Project\node_modules\engine-munger\index.js:133:22
    at C:\Users\Me\Project\node_modules\engine-munger\index.js:154:17
    at C:\Users\Me\Project\node_modules\engine-munger\index.js:87:21
    at C:\Users\Me\Project\node_modules\engine-munger\index.js:189:13
    at FSReqWrap.oncomplete (fs.js:153:5)

Any idea how I can solve this everlasting problem? Thanks!

Edit:

It appears that I can not return anything from the data variable inside any rethinkdb connection or promise, it has to be outside of it to get detected.

P. Nick
  • 955
  • 1
  • 12
  • 33
  • The code probably doesn’t do what you want it to do at all. The function doesn’t rerun anything. What is the purpose of `data`? Also, converting a value to JSON just to parse it again is as if you where conveying a number to a string and back (`parseInt('' + 42, 10)`): it’s completely useless, you better not stringify the value in the first place (`42`). – Felix Kling May 01 '18 at 14:37
  • @FelixKling The purpose of `data` is to hold an object so I can loop it in my template file with `each`. I got the stringify part from the official RethinkDB docs, so I just assumed that was the way to do it because everything else failed as well. – P. Nick May 01 '18 at 14:49
  • In the code in your question, `data:` is a [**label**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label), not a property. You are missing `{...}` around `data:` to make it a property. You might want to read [How do I return the response from an asynchronous call?](https://stackoverflow.com/q/14220321/218196) – Felix Kling May 01 '18 at 21:01

2 Answers2

1

Try to replace your code with this one:

const r = require('rethinkdb');

module.exports = function indexModel() {
  return new Promise((resolve, reject) => {
    const params = {
      host: '127.0.0.1', 
      port: 28015
    };
  
    r.connect(params, (err, conn) => {
      // check availability
      if (error) return reject(error);
    
      r.db('mydb')
       .table('mytable')
       .run(conn)
       .then(cursor => {
          cursor.toArray((error, result) => {
            if (error) return reject(error);
            
            const data = JSON.stringify(result, null, 2);
            return resolve({
              data: data
            });
          });
        });
    });
  });
}
woolfi makkinan
  • 189
  • 1
  • 3
  • Thanks for the answer, but nothing is bound to the `data` variable, which I need to be able to loop through the object in my template file. How would that be accomplished using this method? – P. Nick May 01 '18 at 15:03
  • @P.Nick check it now. The function `indexModel` returns a Promise which returns `data` parameter if all is success – woolfi makkinan May 01 '18 at 15:16
  • thanks, but it is still giving me `Cannot read property 'length' of undefined` – P. Nick May 01 '18 at 15:17
  • Are you sure you have any data inside a DB? if you don't, insert something and try it again – woolfi makkinan May 01 '18 at 15:27
  • Yes there is data, as I said in the post I can console.log the result and it prints the json correctly. As a side note, I can't seem to return anything with the `data` variable inside any rethinkdb connection or promise, not even with raw data. – P. Nick May 01 '18 at 15:28
  • I think that a problem is in your template engine. Can you tell me which one do you use? – woolfi makkinan May 01 '18 at 15:41
  • Pug doesn't allow you to use data from callbacks or Promises. So, you should use it in the next way: `indexModel().then(object => runTemplate(object))` – woolfi makkinan May 01 '18 at 20:03
1

Using async/await might work for you

mymodule.js

module.exports = async function IndexModel() {
        let conn = await r.connect({host: '127.0.0.1', port: 28015});
        let cursor = await r.db('mydb').table('mytable').run(conn)
        try {
            let arr = await cursor.toArray();
            return arr
        } catch (e) {
            throw e;
        }
}

main.js

let indexModel = require('mymodule.js');

indexModel().then(result => {
    console.log(result.length)
})
Evya
  • 2,325
  • 3
  • 11
  • 22
  • You can return `{data: result}` if you like – Evya May 01 '18 at 16:20
  • I tried as you suggested with returning `{data: result}` and it gives me this error: https://pastebin.com/NhAZcapS Furthermore it prints `1` as the length in console. – P. Nick May 01 '18 at 16:27
  • It appers to somewhat "work" when I pass the result to the render function instead of parsing the result. However the deprecation warning still stands, and whats weirder is that it prints like 50 items (there's only 1) and I can not access any of the key values, they are all empty. if I print the result to console it says `{ mytable: '[\n {\n "id": "307ad5e9-a0db-461b-a564-081d73f9b34f",\n "title": "hello"\n }\n]', _locals: { _csrf: 'FpoZxyUSuMK5Sl09juoXWwEFiEoJXiZsLqiYM=' } }` so this is confusing. – P. Nick May 01 '18 at 16:36
  • I have edited my answer - this happens when your data is already an object, and your trying to call `JSON.parse` on it. Try removing it and see if that helps. Also, as was mentioned before, There's no need to call `JSON.stringify` on the results from the database if you're planning on parsing them again. just return `arr` and logging it and it should work. – Evya May 01 '18 at 16:38
  • Didn't see your latest comment. Thanks! It works like a charm now. I'm so happy this problem finally got solved after days of trying to figure it out :) – P. Nick May 01 '18 at 16:40