Search code examples
node.jsmongodbmongoosemongodb-querymongoose-schema

Return single key from MongoDB using Mongoose


The only thing that I' trying to do is return the messages key from a MongoDB using Mongoose in Express, but this is proving to a bit more difficult that it should, mainly because of all the old answers and ways of doing this. So it though it best to ask around and leave something behind for anyone trying to achieve the same things.

This is the schema that contains the messages key:

const UserMessagesScheme = new mongoose.Schema({
    email: {
        type: String,
        required: true
    },
    messages: {
        type: Object,
        required: true,
        default: {}
    }
}, {minimize: false});

What I've tried:

const messages = await Messages.findOne({email}, general).schema.paths.messages;
const messages = await Messages.findOne({email}, general).schema.tree.messages;
const messages = await Messages.findOne({email}, general).lean().messages;
const messages = await Messages.findOne({email}, general).lean().exec((err, res) => res.messages);
const messages = await Messages.findOne({email}, general).lean().exec((err, res) => res._doc.messages);
const messages = await Messages.findOne({email}, general).lean().exec((err, res) => res.toObject().messasges);

// And a heck of a lot more...

console.log(resData.messages);

What works?

const messages = await Messages.findOne({email}, general).then(res => res.messages);

console.log(resData.messages);

Although I've managed to get it to work with .then() I'm not quite sure it's practical, because as you can probably tell this line of code is executed inside of a async function, as such I'd like to find a way to keep things clean by using the same implementations.

Another way of doing this that worked was something like this:

const messages = await Messages.findOne({email}, general).lean();
const messagesFromMessages = messsages.messages;

console.log(resData.messages);

I'm pretty sure that I'm missing something and that there's some knowledge that I need to have in order to grasp this, as such and since other people might be running into this again I'd really love some doc links or something explaining what I don't know besides a code example of: this is what you should have done, please.

Cheers everything!


Solution

  • Mongoose model's findOne returns a promise that either needs to be awaited or continued using .then() / callback style. In all of your cases await gets applied after the entire chain of method calls/field reads so you need parenthesis to enforce await to be executed first and database response to come back. Otherwise, you're trying to read from a pending promise (before the database yields the result), try:

    (await Messages.findOne({email}, general)).messages
    

    or

    let databaseResponse = await Messages.findOne({email}, general)
    let messagse = databaseResponse.messages;