2

I'm setting up a backend on mongoose and GraphQL and I'm having some issues with virtual populate in mongoose.

This is a node.js application running on version 5.4.0 of mongoose and version 11.5.0 of node. I've attempted to follow these two guides without success

http://thecodebarbarian.com/mongoose-virtual-populate https://thecodebarbarian.com/mongoose-4.13-virtual-populate-dynamic-refs-fields

const gameStatusSchema = new mongoose.Schema({
    userID: String,
    gameID: { type: mongoose.Schema.Types.ObjectId, ref: "Game"},
    gameStatus: Number
}, {
    timestamps: true,
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
});

const gameSchema = new mongoose.Schema({
    gameTitle: String,
    gameDescription: String,
    gameType: Number,
    gameTypeID: String,
    gamePosition: Number,
}, {
    timestamps: true,
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
});

gameSchema.virtual("gameStatus", {
    ref: "GameStatus",
    localField: "_id",
    foreignField: "gameID",
    justOne: true
});

const newGame = await Game.findById(id)
.populate("gameStatus");
console.log(newGame);

The newGame object doesn't even contain the gameStatus property. If i add .toJSON({virtuals: true}) gameStatus shows as null.

Below are examples of the JSON objects from mongo

gameStatus object
{
    "_id" : ObjectId("5c473a872721eb7327377fa2"),
    "userID" : "5c3629deed4593ab3b435614",
    "gameID" : ObjectId("5c472bc4b6b5f745bbbd7f6a"),
    "gameStatus" : 8
}

game Object
{
    "_id" : ObjectId("5c472bc4b6b5f745bbbd7f6a"),
    "gameTitle" : "Lotto",
    "gameDescription" : "Test",
    "gameType" : 1,
    "gameTypeID" : "5c472bc4b6b5f745bbbd7f69",
    "gamePosition" : 8,
    "course" : ObjectId("5c35e5e53757a7a29c33565f"),
    "createdAt" : ISODate("2019-01-22T14:42:12.267Z"),
    "updatedAt" : ISODate("2019-01-22T14:42:12.267Z"),
    "__v" : 0
}

I would expect the code above to let me query my game object and get the game object with the virtually populated gameStatus object, but it returns null. Would love it if someone can take a look at my problem.

Jørgen Vik
  • 726
  • 1
  • 8
  • 27
  • can you show me where you are creating models? And how you are creating it? – Muhammad Faizan Jan 23 '19 at 12:35
  • 1
    I'm not sure if I understand your question @MuhammadFaizan. They are created in separate files. Mongoose is imported, and the model is exported. The folder with models has an index.ts file where all the models are exported as modules. `const Game = mongoose.model("Game", gameSchema); export default Game; ` – Jørgen Vik Jan 23 '19 at 12:52
  • I don't think it's related, but you should add toJSON & toObject into the options next to timestamps: true – BenSower Jan 23 '19 at 13:15
  • @BenSower Yes. I'm requesting the following ID, which is represented in both of the objects above: 5c472bc4b6b5f745bbbd7f6a. Also I tried to move toJSON & toObject into the curly bracket which contains timestamps, but it made no difference. – Jørgen Vik Jan 23 '19 at 13:19
  • can you check out this standalone gist and see if it works for you? https://gist.github.com/BenSower/d20479c18cdd77ded3cf1dbbb0230b50 It's using mongoose 5.4.2 and mongodb 3.6.3 – BenSower Jan 23 '19 at 13:25
  • @BenSower The gist you sent me is running perfectly and the object is populated correctly, but I don't understand where I f*ked up in my code. I even installed the same mongoose version. – Jørgen Vik Jan 23 '19 at 13:35
  • Ok, can you then also create a very minimalistic gist of your whole code-setup to reproduce the issue? – BenSower Jan 23 '19 at 13:56
  • I tried to reproduce the problem in a gist, but I literally can't. However I enabled mongoose debugging, and I see from my logs that mongoose is trying to look in a collection called "gamestatuses" instead of "GameStatus". Funny enough I can't find "gamestatuses" anywhere in my code. `Mongoose: gamestatuses.findOne({ gameID: ObjectId("5c472bc4b6b5f745bbbd7f6a") }, { projection: {} })` – Jørgen Vik Jan 23 '19 at 14:31

2 Answers2

0

Something went wrong when the collection was named. Mongoose usually adds "es" to the collection name, as in plural. I figured this out after enabling debugging in mongoose mongoose.set("debug", true); and seeing that it was looking for the wrong collection. In this instance the collection name was missing "es".

This stack overflow thread explains it a little bit

Why does mongoose always add an s to the end of my collection name

I solved it by adding collection: "gameStatus" to my mongoose schema options.

Jørgen Vik
  • 726
  • 1
  • 8
  • 27
0

By default virtual field are not active.
You should set them as active fields. Like this

user.set('toObject', { virtuals: true });    // add this
user.set('toJSON', { virtuals: true });      // add this

or this if required

user.set('toObject', { virtuals: true });    // add this
user.set('toJSON', { virtuals: true });      // add this
user.plugin(mongooseLeanVirtuals);           // add this
D. Schreier
  • 1,700
  • 1
  • 22
  • 34
afshar003
  • 765
  • 6
  • 6