Search code examples
mongoosemongoose-schema

mongoose find subdocs with id, CoreMongooseArray vs DocumentArray


I got a relationship between 2 schemes, for the sake of simplicity lets call it parent => children.

const ChildScheme = new mongoose.Schema(
    {
        name: { type: String, required: true },
    },
    {
        timestamps:true
    });

const child = mongoose.model("Child", Child);

const ParentScheme = new mongoose.Schema(
    {
        name: { type: String, required: true },
        children: [{type: mongoose.Schema.Types.ObjectId, ref: Child, autopopulate: true}],
    },
    {
        timestamps:true
    });

Now I want to get a specific child from a specific parent through an the child's id.

What I tried was:

models.Parent.findById('parent_obj_id')
    .then((parent) => {
        let child = parent.children.id('child_id')
    });

This however does not work, children is of the type CoreMongooseArray, which does not have the function id.

I've searched bit through the source code and I can see that the class CoreDocumentArray which extends from CoreMongooseArray does have that function.

Why do I get a CoreMongooseArray? Is this not working because in actual the mongoose

when I execute the following:

models.Parent.findById('parent_obj_id')
    .then((parent) => {
        console.log(parent);
    });

I will get this response:

{ children:
   [ { name: [],
       _id: 5dbd9723533e204ab91ccee5,
       name: 'peter',
       createdAt: 2019-11-02T14:48:03.763Z,
       updatedAt: 2019-11-02T14:48:03.763Z,
       __v: 0 } ],
  _id: 5dbd9723533e204ab91ccee3,
  name: 'Walter',
  createdAt: 2019-11-02T14:48:03.596Z,
  updatedAt: 2019-11-02T14:48:03.806Z,
  __v: 3 }

Solution

  • After you find the parent, you can access the specific child using javascript array find like this:

    models.Parent.findById("parent_obj_id").then(parent => {
      let child = parent.children.find(c => c._id.toString() === "child_id");
      console.log(child);
    
      //todo: send response
    });
    
    

    I made a simple demo like this:

    (I guess you are using https://www.npmjs.com/package/mongoose-autopopulate package for autopopulate feature)

    Parent model (Team):

    const mongoose = require("mongoose");
    
    const teamSchema = new mongoose.Schema({
      name: {
        type: String,
        required: true,
        unique: true,
        trim: true
      },
      players: [
        {
          type: mongoose.Schema.Types.ObjectId,
          ref: "Player",
          autopopulate: true
        }
      ]
    });
    
    teamSchema.plugin(require("mongoose-autopopulate"));
    
    const team = mongoose.model("Team", teamSchema);
    module.exports = team;
    

    Child model: (Player)

    const mongoose = require("mongoose");
    
    const playerSchema = new mongoose.Schema({
      name: String
    });
    
    const player = mongoose.model("Player", playerSchema);
    module.exports = player;
    

    I have 3 players like this:

    [
        {
            "_id": "5dbdb7cf0101fb08b434a576",
            "name": "player 1",
            "__v": 0
        },
        {
            "_id": "5dbdb7d80101fb08b434a577",
            "name": "player 2",
            "__v": 0
        },
        {
            "_id": "5dbdb7e00101fb08b434a578",
            "name": "player 3",
            "__v": 0
        }
    ]
    

    I have 1 team with those 3 players like this:

    [
        {
            "players": [
                "5dbdb7cf0101fb08b434a576",
                "5dbdb7d80101fb08b434a577",
                "5dbdb7e00101fb08b434a578"
            ],
            "_id": "5dbdb80d0101fb08b434a579",
            "name": "team 1",
            "__v": 0
        }
    ]
    

    To get the team 1's player 1 info, I use the following route:

    router.get("/team/:teamId/:playerId", (req, res) => {
      const { teamId, playerId } = req.params;
    
      Team.findById(teamId).then(team => {
        const player = team.players.find(p => p._id.toString() === playerId);
        res.send(player);
      });
    });
    
    

    And the result is:

    {
        "_id": "5dbdb7cf0101fb08b434a576",
        "name": "player 1",
        "__v": 0
    }