0
\$\begingroup\$

I am faced yet again with a callback headache:

Simply I need to return to the client the results of multiple mongo queries, the number of which I don't know in advance. In short:

  • fetch the first document in a collection
  • if the document has some fields with alphabetic values, fetch all distinct values

Since I can only do the next query in the result callback of the previous one, that's what am doing keeping track of how many fields I have queried so far:

function getFieldsFromCollection (collection, socket) {
 MongoClient.connect(MAIN_DB, function (err, db) {
 if (err) {
 return console.log(err)
 }
 var c = db.collection(collection)
 c.findOne({}, {}, function (err, doc) {
 if (err) {
 return log(err)
 }
 if (!doc) {
 return log('document is null')
 } else {
 var alphaFields = []
 Object.keys(doc).forEach(function (key) {
 if (/^[A-Z]/.test(doc[key])) {
 alphaFields.push(key)
 }
 })
 // prepare the response
 var reply = {
 alphaFields: alphaFields,
 alphaFieldsValues: {}
 }
 fetchDistinctValues(c, alphaFields, 0, reply, socket)
 }
 })
 })
}
function fetchDistinctValues(collection, fields, index, reply, socket) {
 if (index < fields.length) {
 collection.distinct(fields[index], function (err, docs) {
 reply.alphaFieldsValues[fields[index]] = docs
 fetchDistinctValues(collection, fields, ++index, reply, socket)
 })
 } else {
 socket.emit('getFieldsFromCollectionReply', reply)
 }
}

Needless to say this feels very hackysh.. I've looked into some libraries or promises but they seem to offer solution for when one knows exactly how many queries have to be made. Please tell me there is a better way

asked Oct 30, 2017 at 12:03
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I'm pretty sure Mongo has native Promise support, that in conjunction with async/await would really tidy this up

async getFieldsFromCollection (collection, socket) {
 try {
 const db = await MongoClient.connect(MAIN_DB);
 const c = db.collection(collection);
 const doc = await c.findOne({}, {});
 if (!doc) throw new Error('document is null');
 const alphaFields = Object.keys(doc).filter(k => /^[A-Z]/.test(doc[k]));
 const alphaFieldsValues = {};
 const subQueries = alphaFields.map(async (f) => {
 const docs = await c.distinct(f);
 alphaFieldsValues[f] = docs;
 });
 await Promise.all(subQueries);
 return socket.emit('getFieldsFromCollectionReply', {
 alphaFields,
 alphaFieldsValues
 });
 } catch (e) {
 return log(e);
 }
}
answered Nov 12, 2017 at 1:13
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.