MongoDB Push to Array, then res.json not working?

I have a character model which has an array of object id refs as the “inventory”. Each object id references an “equipment” with various stats. I want to get return an array that shows the stats, not the object ids. I thought I would forEach the array and findOne each of these equipments, then push their stats to the inventoryItems array.

Problem is this: Even though I can see with console.log that each item is being looked up successfully, when I log the array it comes out as empty.

        Promise.all(promises).then(console.log(inventoryItems));

I put it in promises but that still doesn’t work. Why might this be happening?

    let promises = [];
    let inventoryItems = [];
    Character.findOne({ user: req.user.id })
      .then(character => {
        character.inventory.forEach(item => {
          promises.push(
            EquipmentClass.findById(item._id).then(item => {
              inventoryItems.push(item);
            })
          );
        });
        Promise.all(promises).then(console.log(inventoryItems));
      })
      .then(res.status(200).json({ inventory: "" }));

Repo:

I am coming across a similar problem in my code (which I haven’t fixed).
If I was doing this as a relational database you would have a link table to link items and users as it is a many to many relationship.
Here I am thinking have a “user inventory” collection having UserId and an array of Equipment items.
Not sure the best way to do this in MongoDb. :thinking:

The inventory, as part of a character in the characters collection is working. It properly holds an array of object ids with a reference to the equipment collection. The problem comes when trying to return not just the object ids, but the actual objects themselves. If I console log them in the forEach statement it shows the correct items. It is just not pushing them to a new array like I would want.

@SnowdenWintermute I cloned your repo, but not sure how to install. I noticed you are using gulp and gulp-sass, but do not have those as part of your package.json. You might want to make sure you provide some setup instructions in your README.md file.

I do not have an answer for the question you asked, because I could not successfully run npm run dev, but I was looking at one of your files (generateSubType.js) located in:

utils/equipmentGenerationUtils/generateSubType.js

and thought you might consider using a lookup object instead of all of those if statements:

module.exports = generateSubType = type => {
  // Generate Sub-Type
  const armors = ["cloth", "leather", "mail", "plate"];
  const weapons = [
    "1hSword", "2hSword", "1hClub", "2hClub",
    "1hAxe", "2hAxe", "polearm", "bow",
    "crossbow", "pistol", "rifle", "shield"
  ];
  const ammunitions = ["arrow", "bolt", "bullet"];

  const subTypeLookup = {
    head: armors,
    body: armors,
    legs: armors,
    feet: armors,
    shoulders: armors,
    arms: armors,
    hand: armors,
    back: armors,
    hand: weapons,
    ammunition: ammunitions,
    ring: ["ring"],
    neck: ["neck"]
  };

  const subTypes = subTypeLookup[type];
  const rn = getRandomInt(0, subTypes.length - 1);
  return subTypes[rn];
};
1 Like

Thanks, I have added to my readme and I will try out this lookup object. I like it, much more clean way to do it.

To build this app: run npm install and npm install -D in both the client folder and the main (server) folder. The gulp and gulp sass are dev dependencies in the package json of the client folder.

I think I got the solution:

forgot to put anonymous callback function in the “then” after the promise.all. I also moved the res into the same “then”.

    let promises = [];
    let inventory = {
      items: []
    };
    Character.findOne({ user: req.user.id }).then(character => {
      character.inventory.forEach(item => {
        promises.push(
          EquipmentClass.findById(item._id).then(item => {
            inventory.items.push(item);
          })
        );
      });
      Promise.all(promises).then(() => {
        console.log("items:");
        console.log(inventory);
        res.status(200).json(inventory);
      });