mongodbmlabserverlesswebtaskfaas

How to get all documents of a collection with mongodb find() using webtask.io and mlab


I have a collection named "posts" in a mongodb at mlab.com and I am trying to access all of the documents in this collection with db.collection('posts').find(). Below is my code for my webtask I've created, which I named mongodb_find:

var MongoClient = require('mongodb').MongoClient;
var waterfall   = require('async').waterfall;

/**
 * @param {secret} MONGO_URL - Mongo database url
 */
module.exports = function(ctx, cb) {

    var MONGO_URL = ctx.data.MONGO_URL;
    if (!MONGO_URL) return cb(new Error('MONGO_URL secret is missing'))

    waterfall([
        function connect_to_db(done) {
            MongoClient.connect(MONGO_URL, function(err, db) {
                if(err) return done(err);
                done(null, db);
            });
        },

        function find_hits(db, done) {
            db
            .collection('posts')
            .find(
                {},
                function (err, result) {
                    if(err) return done( err );
                    done( null, JSON.stringify(result) );
                }
            ).sort({ hits: -1 }).limit( 2 );
        }

    ], cb);

};

I have a mongodb_upsert webtask that is very similar to this and works perfectly. However, for my mongodb_find task I am getting the following error:

{
  "code": 400,
  "error": "Error when JSON serializing the result of the JavaScript code.",
  "details": "TypeError: Converting circular structure to JSON",
  "name": "TypeError",
  "message": "Converting circular structure to JSON",
  "stack": "TypeError: Converting circular structure to JSON\n    at Object.stringify (native)\n    at /data/sandbox/lib/sandbox.js:775:48\n    at /data/sandbox/node_modules/async/dist/async.js:473:16\n    at next (/data/sandbox/node_modules/async/dist/async.js:5315:29)\n    at /data/sandbox/node_modules/async/dist/async.js:958:16\n    at /data/io/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/webtask.js:27:6\n    at handleCallback (/data/_verquire/mongodb/2.0.48/node_modules/mongodb/lib/utils.js:96:12)\n    at Collection.find (/data/_verquire/mongodb/2.0.48/node_modules/mongodb/lib/collection.js:354:44)\n    at find_hits (/data/io/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/webtask.js:23:5)\n    at nextTask (/data/sandbox/node_modules/async/dist/async.js:5310:14)"
}

When connecting to mongodb from the command line the same find() command works properly:

db.posts.find({}).sort({hits: -1}).limit(2);

The documents in the collection are set up like this:

{
    "_id": {
        "$oid": "5a3ff239bda4eaa4ab96ef8b"
    },
    "title": "Testing 6",
    "url": "/jquery/2017/12/22/testing-6.html",
    "hits": 2
}

Does anyone know of a solution to this issue? Thank you.


Solution

  • Collection.find returns a cursor, not the results of the query. You probably want to chain all your operations such as sort and limit on the cursor, then use toArray to define the callback. toArray will retrieve the results from the cursor.

    For example:

    function find_hits(db, done) {
      db.collection('posts')
        .find({})
        .sort({ hits: -1 })
        .limit(2)
        .toArray(function (err, result) {
          if(err) return done( err );
          done(null, JSON.stringify(result));
        });
    }