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
1 Answer 1
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);
}
}
Explore related questions
See similar questions with these tags.