0

This is my code for sending data to a database:

app.post('/thanks', function(req, res) {
  if (atendees.checkin === req.body.dbstring) {
    dbConn.then(client => {
      delete req.body._id;
      const db = client.db('mydata')
      db.collection(atendees.checkin).insertOne(req.body);
    })
(...)

This is how I display on the page after clicking on a href link:

app.get('/view-feedbacks',  function(req, res) {
    dbConn.then(client => {
      const db = client.db('mydata')
      db.collection(atendees.checkin).find({}).toArray().then(function(feedbacks) {
            res.status(200).json(feedbacks);
            atendees.checkin = ' '
          }).catch(err => {
            throw(err);
          })
    });

});

That works fine. How can I do something similar to display all collections from the database instead of just the individual ones?

This is what I tried to do:

app.get('/view-history',  function(req, res) {
  dbConn.then(client => {
    const db = client.db('mydata')
    db.listCollections().toArray().then(function(collInfos) {
          res.status(200).json(collInfos);
          atendees.checkin = ' '
        }).catch(err => {
          throw(err);
        })
  });
});

But it just gives me the name of each collection. I want to show all collections and all of their elements.

Edit: my question is different from this one: MongoDB Show all contents from all collections .I'm trying to do this on express.js, not on the terminal

Edit2: Using db.collection:

app.get('/view-history',  function(req, res) {
  dbConn.then(client => {
    const db = client.db('mydata')
    db.collections().then(function(feedbacks) {
          res.status(200).json(feedbacks);
          atendees.checkin = ' '
        }).catch(err => {
          throw(err);
        })
  });

But this gives the error: TypeError: converting circular structure to JSON

Peplm
  • 43
  • 1
  • 8

2 Answers2

0

Have you tried just db.collections()? If that also doesn't give what you need, you might have to invoke db.collection(<name>) on each of the names you get from listCollections.

Vasan
  • 4,810
  • 4
  • 20
  • 39
  • Using db.collections() gives "TypeError: Converting circular structure to JSON". Do I have to change anything else in the code? – Peplm Mar 24 '18 at 01:54
  • I edited the question with my code using db.collections() – Peplm Mar 24 '18 at 01:56
0

With async/await, this could be done:

app.get('/view-history', async (req, res) => {
    try {
        const client = await dbConn;
        const db = client.db('mydata');

        let collections = await db.collections();
        let documents = await Promise.all(collections.map(async (collection) => {
            let documents = await collection.find({}).toArray();
            return Promise.resolve([collection.collectionName, documents]); // Retain collectionName
        }));

        // Format into an object that looks like `collectionName: documents`
        let formatted = documents.reduce((obj, collection) => {
            obj[collection[0]] = collection[1];
            return obj;
        }, {});

        res.json(formatted);
    } catch (e) {
        console.error(e);
        res.sendStatus(500);
    }
});

A Promise-only approach:

app.get('/view-history', (req, res) => {
    dbConn.then((client) => {
        const db = client.db('mydata');
        return db.collections();
    }).then((collections) => {
        return Promise.all(collections.map((collection) => {
            return new Promise((resolve, reject) => {
                collection.find({}).toArray().then((documents) => {
                    resolve([collection.collectionName, documents]);
                }).catch(reject);
            });
        }));
    }).then((documents) => {
        let formatted = documents.reduce((obj, collection) => {
            obj[collection[0]] = collection[1];
            return obj;
        }, {});
        res.json(formatted);
    }).catch((e) => {
        console.error(e);
        res.sendStatus(500);
    });
});

The main reason this code is unnecessarily verbose is because instead of just returning a big array filled with arrays of documents, you probably want an object that retains the name of the collection, like so:

{
    collection1: [...documents...],
    collection2: [...documents...],
    ...
}

Instead of:

[
    [...documents...],
    [...documents...],
    ...
]

If you do want just a big array of each collection without caring about the names of the collections, it becomes much simpler:

async/await version:

app.get('/view-history', async (req, res) => {
  try {
      const client = await dbConn;
      const db = client.db('mydata');

      let collections = await db.collections();
      let documents = await Promise.all(collections.map((collection) => collection.find({}).toArray()));

      res.json(documents);
  } catch (e) {
      console.error(e);
      res.sendStatus(500);
  }
});

Promise-only version:

app.get('/view-history', (req, res) => {
    dbConn.then((client) => {
        const db = client.db('mydata');
        return db.collections();
    }).then((collections) => {
        return Promise.all(collections.map((collection) => collection.find({}).toArray()));
    }).then((documents) => {
        res.json(documents);
    }).catch((e) => {
        console.error(e);
        res.sendStatus(500);
    });
});
Sven
  • 5,155
  • 29
  • 53
  • It does work! The only problem is that the collections are not separated by new lines, but I guess this would be asking too much.. – Peplm Mar 24 '18 at 02:45
  • By default Express does not output "prettified" JSON. You could use [express-prettify](https://www.npmjs.com/package/express-prettify) or a Browser plugin like [JSON Formatter](https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa?hl=en) though! – Sven Mar 24 '18 at 02:53