简体   繁体   中英

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

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
    }
]

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 })

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'})

Query using the populate method

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM