Home > OS >  One to many with MongoDB (Mongoose) with .populate()
One to many with MongoDB (Mongoose) with .populate()

Time:01-17

What I am doing

I am trying to return a player by playerId with all ref items from each object in it's schema. In this example, I am specifically talking about the players inventory.

How can I return all reference items and their properties?

In my service file, I am getting my player with:

/**
 * Get a player by playerId
 * @param playerId
 * @returns {Promise<*>}
 */
module.exports.getPlayer = async (playerId) => {
  return await Player.findOne({ playerId: playerId }).populate('inventory');
};
And this is my returned JSON
{
    "success": true,
    "data": {
        "_id": "63bb1f3ec17d33f4d2a87194",
        "playerId": 4183489039,
        "name": "AlanGreyjoy",
        "currency": {
            "copper": 500,
            "silver": 10,
            "gold": 0
        },
        "online": false,
        "inventory": [
            {
                "currentDurability": 0,
                "item": "63ba0c54407456969ba38615",
                "amount": 1,
                "_id": "63bc4fa070eaa247288e3573",
                "createdAt": "2023-01-09T17:32:16.643Z",
                "updatedAt": "2023-01-09T17:32:16.643Z"
            }
        ],
        "bank": [],
        "questTracker": [],
        "friends": [],
        "knownRecipes": [],
        "jobs": [],
        "createdAt": "2023-01-08T19:53:34.903Z",
        "updatedAt": "2023-01-09T17:32:16.643Z",
        "__v": 1
    }
}

As you can see, the item in the inventory array is not populating with the ref item from the items collection.

I have googled and googled and tried so many different things, but nothing is working.\

The item does exist in the db enter image description here

My Models

My Player.model.js

const mongoose = require('mongoose');
const toJSON = require('../plugins/mongoToJson');

const Schema = mongoose.Schema;

const questTracker = new Schema(
  {
    quest: { type: mongoose.Schema.Types.ObjectId, ref: 'Quest' },
    complete: { type: Boolean, default: false },
  },
  { timestamps: true }
);

const friends = new Schema(
  {
    player: { type: mongoose.Schema.Types.ObjectId, ref: 'Player' },
    isFavorite: { type: Boolean, default: false },
  },
  { timestamps: true }
);

const knownRecipes = new Schema(
  {
    recipe: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
  },
  { timestamps: true }
);

const jobs = new Schema(
  {
    job: { type: mongoose.Schema.Types.ObjectId, ref: 'Job' },
  },
  { timestamps: true }
);

const inventoryItems = new Schema(
  {
    item: { type: mongoose.Schema.Types.ObjectId, ref: 'Item' },
    amount: { type: Number, default: 0 },
    currentDurability: { type: Number, default: 0 },
  },
  { timestamps: true }
);

const bank = new Schema(
  {
    item: { type: mongoose.Schema.Types.ObjectId, ref: 'Item' },
    amount: { type: Number, default: 0 },
  },
  { timestamps: true }
);

const playerSchema = new Schema(
  {
    playerId: {
      type: Number,
      unique: true,
      required: true,
    },
    name: {
      type: String,
      required: true,
      unique: true,
    },
    currency: {
      type: Object,
      default: {
        copper: 500,
        silver: 10,
        gold: 0,
      },
    },
    inventory: [inventoryItems],
    bank: [bank],
    questTracker: [questTracker],
    friends: [friends],
    knownRecipes: [knownRecipes],
    jobs: [jobs],
    online: {
      type: Boolean,
      default: false,
    },
  },
  { timestamps: true }
);

const PlayerModel = mongoose.model('player', playerSchema);

module.exports = PlayerModel;

My Item.model.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const toJSON = require('../plugins/mongoToJson');

const vendorPriceSchema = mongoose.Schema({
  copper: {
    type: Number,
    default: 0,
  },
  silver: {
    type: Number,
    default: 0,
  },
  gold: {
    type: Number,
    default: 0,
  },
});

const itemSchema = new Schema(
  {
    title: {
      type: String,
      required: true,
      unique: true,
    },
    assetId: {
      type: Number,
      required: true,
    },
    description: {
      type: String,
    },
    equipDescription: {
      type: String,
    },
    additionalDescription: {
      type: String,
    },
    consumableUseDescription: {
      type: String,
    },
    itemLevel: {
      type: Number,
    },
    requiredLevel: {
      type: Number,
    },
    type: {
      type: String,
      required: true,
    },
    subtype: {
      type: String,
      required: true,
    },
    stamina: {
      type: Number,
    },
    intellect: {
      type: Number,
    },
    criticalStrike: {
      type: Number,
    },
    agility: {
      type: Number,
    },
    mastery: {
      type: Number,
    },
    maxDurability: {
      type: Number,
    },
    vendorPrice: { vendorPriceSchema },
    minDamage: {
      type: Number,
      default: 0,
    },
    maxDamage: {
      type: Number,
      default: 0,
    },
    speed: {
      type: Number,
    },
    maxStack: {
      type: Number,
    },
  },
  { timestamps: true }
);

const ItemModel = mongoose.model('Item', itemSchema);

module.exports = ItemModel;

CodePudding user response:

You can use something like this:

module.exports.getPlayer = async (playerId) => {
  return await Player.findOne({ playerId: playerId }).populate({
      path: "inventory",
      populate: {
        path: "item",
      },
    });
};
  • Related