Problems with Mongoose populate - node.js

Game schema
const { Schema, model } = require('mongoose');
const gameSchema = Schema({
_id: Schema.Types.ObjectId,
name: { type: String, required: true },
description: String,
calc: [{ type: Schema.Types.ObjectId, ref: 'Calc' }]
});
module.exports = model('Game', gameSchema);
Calc schema
const { Schema, model } = require('mongoose');
const calcSchema = Schema({
_id: Schema.Types.ObjectId,
preset: { type: String, required: true },
datasets: [{ type: Schema.Types.ObjectId, ref: 'Dataset' }],
model: String,
});
module.exports = model('Calc', calcSchema, 'calc');
GET Games route
router.get('/', passport.authenticate('jwt', { session: false }), (req, res) => {
Game.find()
.select('_id name calc')
.populate('calc')
.then(games => res.status(200).json(games))
.catch(err => res.status(500).json({ error: err }));
});
Instead of populating calc property with Calc objects, replacing the ids, calc property turns into an empty array. How do I use populate correctly? Is there an obvious mistake I made in my code?
In short: populate() results in calc: [] instead of calc: [{Calc object}, ...]

In your case you are trying to populate an array of document (and not only one document) so you should use the Model.populate() method instead.
Game.find()
.select('_id name calc')
.then(games => Game.populate(games, { path: 'calc' }))
.then(games => res.status(200).json(games))
.catch(err => res.status(500).json({ error: err }));

Related

Get the data inside request array inside of a schema

How can I create a route to get postedby data which is inside requests array. The request array is inside of a Post schema
const mongoose = require("mongoose")
const {ObjectId} = mongoose.Schema.Types
const postSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
jobtitle:{
type: String,
required: true
},
requests:[{
text: String,
postedby:{type: ObjectId, ref: "User"}
}],
postedby:{
type: ObjectId,
ref: "User"
}
})
mongoose.model("Post", postSchema)
I tried this but I was getting another postedby
router.get("/acceptedpost",requireLogin,(req,res)=>{
Post.find({postedby:req.user._id})
.populate("postedby","_id name")
.then(accpost => {
res.json({accpost})
})
.catch(err => {
console.log(err)
})
})
If you want to match the req.user._id against the requests array, you can simply do:
Post.find({"requests.postedby": req.user._id})
.populate("postedby", "requests.postedby")
.then(accpost => {
res.json({accpost})
})
.catch(err => {
console.log(err)
})

dynamic references by sending it from the route

I have been looking at the documentation and some other questions made, but I have not been able to do it, I need to consult another collection for an objectId, but these collections come dynamically in the routes.
The collections come req, as they are from many different clients
https://mongoosejs.com/docs/populate.html
//route
// example collection dynamic ssdf2451_users, ssdf2451_campus, ssdf2451_programs
router.get('/school/prueba/tipos/', async (req, res, next) => {
let users
let school
let prueba
try {
const Users = model(`ssdf2451_users`, UserSchema)
console.log(Users)
await Users.findOne({ _id: '5ef56f70d19aea6e70c82a50' })
.populate('schoolId')
.exec(function (err, usersDocuments) {
console.log(usersDocuments, err)
// handle err
prueba = usersDocuments
res.status(200).json(prueba)
})
} catch (err) {
next(err)
}
})
// Schema
import { Schema, model } from 'mongoose'
const UserSchema = new Schema({
state: {
type: Boolean,
default: false,
required: false
},
accountNumber: {
type: Number,
required: false
},
schoolId: {
type: Schema.Types.ObjectID,
required: true,
ref: 'schools'
},
campusId: {
type: Schema.Types.ObjectID,
required: true,
ref: dynamic
},
programsId: {
type: [Schema.Types.ObjectID],
required: false,
ref: dynamic
},
})
const User = model('users', UserSchema)
export { User, UserSchema }

How to pass an ObjectId into a POST request?

I am trying to make a One-To-Many relationship between two tables(Group and Movement tables) using node js (Express) and mongo DB. I already have a group Id coming from the Group table on my side, my question is, how can I save a movement( see point 3 ) with that group Id I have. I tried passing groupId: req.body.group._id and
groupId: req.body.group but I am never able to populate that variable
This are the two entities I've created:
1) GROUP ENTITY
const mongoose = require("mongoose")
const GroupSchema = mongoose.Schema({
name: {
type: String,
required: true
},
limit: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
movement: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Movement' }],
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
})
module.exports = mongoose.model("Group", GroupSchema)
2) MOVEMENT ENTITY
const mongoose = require("mongoose")
const MovementSchema = mongoose.Schema({
description: {
type: String,
required: true
},
value: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
group: { type: mongoose.Schema.Types.ObjectId, ref: 'Group' }
})
module.exports = mongoose.model("Movement", MovementSchema)
This is my movement router where I make the endpoints (Actual problem is here)
3) MovementRoute
const router = require('express').Router();
const verify = require('./verifyToken');
const User = require('../model/User');
const Group = require('../model/Group');
const Movement = require('../model/Movement');
// Create Movement
router.post('/', verify, async (req, res) => {
const post = new Movement({
description: req.body.description,
value: req.body.value,
groupId: req.body.group._id //**tried this**
});
try {
const savedMovement = await post.save()
res.status(200).send(res.json({ data: savedMovement }));
} catch (error) {
res.status(400).send(res.json({ message: error }));
}
});
module.exports = router;
Request sent
{
"description":"group1",
"value":"233",
"group":"5e506f3c56233d08f79bc8f3"
}
If console.log(req.body) gives you this:
{
description: 'group1',
value: '233',
group: '5e506f3c56233d08f79bc8f3'
}
..you should be able to do this:
router.post('/', verify, async (req, res) => {
console.log(req.body) // --> { description: 'group1', value: '233', group: '5e506f3c56233d08f79bc8f3' }
const post = new Movement({
description: req.body.description,
value: req.body.value,
groupId: req.body.group
// groupId: req.body.group._id //**tried this**
});
try {
const savedMovement = await post.save()
res.status(200).send(res.json({ data: savedMovement }));
} catch (error) {
res.status(400).send(res.json({ message: error }));
}
});

How do I join two mongodb collections together using a mongoose controller route?

Sorry, I'm pretty new with node.js and express. I'm trying to setup a mongoose schema that will allow a user to create a character and store that character in the collection associated with that User. I have two schemas, one for user and one for character.
So far, I have tried using .populate, I've tried pushing into the user array on my character schema. And it doesn't return the results i'm wanting.
Here are my schema's and my route file that should be setup to create a new user, and a character. But i'm not sure how to attach that newly created character to my user. When I tried some other variations, I was able to get a character ID to save in mongodb under a user but it would overwrite the current characterId already saved in there.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const characterSchema = new Schema({
name: {
type: String,
required: true,
},
job: {
type: String,
required: true,
},
race: {
type: String,
required: true,
},
level: {
type: String,
required: true,
},
image: {
type: String,
},
user: [{
type: schema.Types.ObjectId,
ref: 'User'
}]
});
const Character = mongoose.model('Character', characterSchema);
module.exports = Character;
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('User', userSchema);
module.exports = User;
router.route('/').get((req, res) => {
User.find()
.then(users => res.json(users))
.catch(err => res.status(400).json("Error" + err))
});
router.route('/:id').get((req, res) => {
User.findById(req.params.id)
.then(user => res.json(user))
.catch(err => res.status(400).json("error" + err))
})
router.route('/character').get((req, res) => {
Character.find()
.then(characters => res.json(characters))
.catch(err => res.status(400).json("error" + err))
})
router.route('/character').post((req, res)=> {
const newCharacter = new Character({
name: req.body.name,
job: req.body.job,
race: req.body.race,
level: req.body.level
})
newCharacter
.save()
.then(character => res.json(character))
.catch(err => res.status(400).json("error" + err));
})
im not an expert in node.js nor in mongoose, but i have a little bit experiences.
For me it looks weird, because i think you use from user a reference to the character, or do i missunderstood something?
Because a user has a character.
For the handling:
If the User creates an character and post it, you get the user by the cookie, id or whatelse and then update the character.
Something like:
User.findOneAndUpdate(
{ "_id": userID},
{
"$set": {
"character.$": character
}
},
function(err,doc) {
}
);
So i think this is missing in Usermodel:
character: [{
type: schema.Types.ObjectId,
ref: 'Character'
}]

Cast to ObjectId failed for value "" at path "_id" for model

I have already checked the other entries on StackOverflow, but it did not help.
I am building a RESTapi with node.js, and I am using MongoDB with mongoose
I have a Schema that contains three different models. I am able to save POST request to the entry. I am sure that entry is saved because I checked on atlas.mongo. However, I have a problem when I am trying to use GET request.
It gives this error:
Cast to ObjectId failed for value "" at path "_id" for model
These are my Models: (These models are in different files)
const Model1 = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
word1: { type: [String], require: true }
});
----------------------------------------------
const Model2 = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
word2: { type: [String], require: true }
});
----------------------------------------------
const Model3 = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
element1: { type: [String], default: ""},
element2: { type: [String], default: ""}
});
----------------------------------------------
const Word = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
md3: { type: mongoose.Schema.Types.Mixed, ref: 'Model3', require: true },
md2: { type: mongoose.Schema.Types.Mixed, ref: 'Model2', require: true },
md1: { type: mongoose.Schema.Types.Mixed, ref: 'Model1', require: true }
});
This is my POST request:
exports.entry_create = (req, res, next) => {
const newModel3 = new Model3({
_id: new mongoose.Types.ObjectId(),
element1: req.body.element1,
element2: req.body.element2
});
const newModel2 = new Model2({
_id: new mongoose.Types.ObjectId(),
word2: req.body.word2
});
const newModel1 = new Model1({
_id: new mongoose.Types.ObjectId(),
word1: req.body.word1
});
const newEntry = new Word({
_id: new mongoose.Types.ObjectId(),
md3: newModel3,
md2: newModel2,
md1: newModel1
});
newEntry
.save(); // i have also then() and catch() part
};
This is where I got the error on Postman
exports.entry_get_all = (req, res, next) => {
Word.find()
.select('_id md3 md2 md1')
.populate('md3')
.populate('md2')
.populate('md1')
.exec()
.then(docs => {
res.status(200).json({
numOfEntries: docs.length,
Entries: docs.map(doc => {
return {
_id: doc._id,
md3: doc.md3,
md2: doc.md2,
md1: doc.md1,
request: { type: 'GET' }
}
})
});
}); // i have also catch() part
};
What could be the problem? Is _id's of md3, md2 & md1 returns null?
I believe it has to do with your references md1, md2 and md3. The way you reference another model is by the _id, which in your case it's and ObjectId. That being said, when you define md1, md2, and md3 you say the type is mixed, not an ObjectId. Do this instead:
const Word = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
md3: { type: mongoose.Schema.Types.ObjectId, ref: 'Model3', require: true },
md2: { type: mongoose.Schema.Types.ObjectId, ref: 'Model2', require: true },
md1: { type: mongoose.Schema.Types.ObjectId, ref: 'Model1', require: true }
});
Also note: You don't need to explicitly create a new ObjectId when creating an instance of your model. If using mongoose, it creates the _id for you! So you can just create a new Word like this:
let md1 = null;
let md2 = null;
let md3 = null;
const newModel3 = new Model3({
element1: req.body.element1,
element2: req.body.element2
});
// Save newModel3
newModel3.save()
.then((_md3) => {
md3 = _md3;
const newModel2 = new Model2({
word2: req.body.word2
});
return newModel2.save();
})
.then((_md2) => {
md2 = _md2;
const newModel1 = new Model1({
word1: req.body.word1
});
return newModel1.save();
})
.then((_md1) => {
md1 = _md1
const newEntry = new Word({
md3: md3._id,
md2: md2._id,
md1: md1._id
});
return newEntry.save();
})

Resources