'Mongoose find by reference field

I have a channel schema like this:

const channelSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      unique: true
    }
  }
);

And this is the feedback schema:

const feedbackSchema = new mongoose.Schema({
  channelId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "channel",
    require: true
  }
});

How can I find the feedback by channel name?

Feedback.find({channelId.name : 'something'})

Thanks



Solution 1:[1]

Since you don't have any reference from channel schema to feedback schema, you can use populate-virtuals feature of mongoose.

The required changes are like this:

1-) replace your channel schema like this to use virtual populate:

const mongoose = require("mongoose");

const channelSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      unique: true
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

// Virtual populate
channelSchema.virtual("feedbacks", {
  ref: "feedback",
  foreignField: "channelId",
  localField: "_id"
});

module.exports = mongoose.model("channel", channelSchema);

2-) Use the following query to find feedbacks of a given channel name:

Please note that I hard coded channel name in the query, you can read it from request body or request query or request params.

router.get("/feedback", async (req, res) => {
  const result = await Channel.findOne({ name: "Channel 1" }).populate({
    path: "feedbacks"
  });

  res.send(result);
});

The response will be like this:

[
  {
    "_id": "5de5509476a9c34048c1d23d",
    "name": "Channel 1",
    "__v": 0,
    "feedbacks": [
      {
        "_id": "5de5512d7d87de2d4c6b38d2",
        "channelId": "5de5509476a9c34048c1d23d",
        "__v": 0
      },
      {
        "_id": "5de551357d87de2d4c6b38d3",
        "channelId": "5de5509476a9c34048c1d23d",
        "__v": 0
      }
    ],
    "id": "5de5509476a9c34048c1d23d"
  }
]

Or if you are only interested to feedbacks, you can access them by result.feedbacks:

router.get("/feedback", async (req, res) => {
  const result = await Channel.findOne({ name: "Channel 1" }).populate({
    path: "feedbacks"
  });

  res.send(result.feedbacks);
});

Which will give you an array of feedbacks like this:

[
    {
        "_id": "5de5512d7d87de2d4c6b38d2",
        "channelId": "5de5509476a9c34048c1d23d",
        "__v": 0
    },
    {
        "_id": "5de551357d87de2d4c6b38d3",
        "channelId": "5de5509476a9c34048c1d23d",
        "__v": 0
    }
]

Solution 2:[2]

You cant query for a property on an object that doest exists, I would suggest first querying for the channel, grabbing the id and doing the lookup from there.

const channel = await Channel.findOne({ name });
const feedback = await Feedback.find({ channelId: channel._id })

Solution 3:[3]

You can use plugin mongoose-find-by-reference.

Step.1 install

npm i -S mongoose-find-by-reference

npm link Github link

Step.2 plugin() the plugin

const mongoose = require("mongoose");

// Require mongoose-find-by-reference
const { MongooseFindByReference } = require('mongoose-find-by-reference');

await mongoose.connect("mongodb://localhost:27017/test")

const channelSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      unique: true
    }
  }
);


const feedbackSchema = new mongoose.Schema({
  channelId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "channel",
    require: true
  }
});

// Execute function plugin() on schema with Reference paths
feedbackSchema.plugin(MongooseFindByReference);


const Channel= mongoose.model('channel', channelSchema );
const Feedback= mongoose.model('feedback', feedbackSchema );

Step.3 just use it!

const { _id } = await Channel.create({ name: "C" })

await Feedback.create({channelId : _id})

/** Its conditions will be auto automatically replaced with :
{
  channelId: {
    $in: [
      /* ObjectIDs for Eligible channels */
    ],
  },
}
 */
const findResult = await Feedback.find({channelId.name : 'C'})

Solution 4:[4]

Query using the populate method

try {
  const data = await feedBack.find(...).populate({ path: 'channel', match: { id: 'xxx' }).exec();
} catch (err) {
  console.log(err);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dan Starns
Solution 3 ChezzOne
Solution 4 Jimmy lau