array of object populate returns null mongoose - node.js

This returns null what could be the issue? I see proper user _id in the test table, I would expect user detail to be shown in the place user. As you can see under test array i made ref to user schema.
structure as follows in database
const mongoose = require('mongoose');
let UserSchema = new mongoose.Schema({
email: String,
password: String,
});
let testSchema = new mongoose.Schema({
test: [
{
title: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
},
],
});
run().catch((err) => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await mongoose.connection.dropDatabase();
const UserModel = mongoose.model('user', UserSchema);
const TestModel = mongoose.model('test', testSchema);
const newUser = { email: 'test#test.com', password: 'Alexa123' };
const user = new UserModel(newUser);
await user.save();
const newTest = { test: [{ title: 'foo', user: user._id }] };
const test = new TestModel(newTest);
await test.save();
const getTest = await TestModel.findOne({ title: 'test' })
.populate('test.user')
.exec();
console.log(getTest, 'returns null');
}

anyway solved by this
const getTest = await TestModel.findOne({ _id: test._id })
.populate('test.user')
.exec();

Related

MongoError: text index required for $text query

I am getting text index required for $text query where as i already did index before using that schema. Can someone tell me what could be the issue?. One more question Do we need to drop table in mongodb to create index? if yes then i will loose my current data. how can i do indexing without dropping the table?
const mongoose = require('mongoose');
let UserSchema = new mongoose.Schema({
email: String,
title: String,
});
UserSchema.indexes({ email: 'text', title: 'text' });
run().catch((err) => console.log(err));
async function run() {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
await mongoose.connection.dropDatabase();
const UserModel = mongoose.model('user', UserSchema);
await UserModel.createIndexes();
const newUser = [
{ email: 'test#test.com', title: 'r' },
{ email: 't#gmail.com', title: '#ro' },
];
const user = await UserModel.create(newUser);
console.log(user, 'user');
const index = await UserModel.listIndexes();
console.log(index);
const data = await UserModel.find({ $text: { $search: 'test' } }).exec();
console.log(data);
}
The function UserSchema.indexes returns the current indexes that are defined on the schema. You want UserSchema.index that defines a new index.

mongoose populate in array of custom objects

In the user model, I have an array of custom objects followedPlaylists which contains two attributes ( playlist: the id of the playlist, public: to determine whether it is public or not) as shown below
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
I want to populate on followedPlaylists.playlist so the response would be something like
[{
playlist: * the actual playlist object *,
public: true
}]
I hope my question is clear enough and thanks in advance.
Here I am assuming that your Playlist is working just fine. i.e., it has elements and has been tested independently.
So, given the schema:
Const Playlist = require (./Playlist)//here you have to provide the path to the Playlist model or use mongoose.model (“Playlist”) to bring it in
………….
const userSchema = new mongoose.Schema({
..... other attributes
followedPlaylists: [{
playlist: {
type: mongoose.Schema.ObjectId,
ref: 'Playlist',
unique: true
},
public: Boolean
}]
})
On whatever you want to print it, just make something like:
Const user = mongoose.model (“User”);//or use require, what fits best your applications
……
Console.log(user.find().populate(“Playlist”))//here is the trick, you ask to populate the Playlist
Example
Examples are the best way to grasp a concept. You can play around with this example:
//------------------------------------------------------------------
const mongoose = require("mongoose");
const { model, Schema } = require("mongoose");
var dbURI = "mongodb://localhost/mongoose-sample";
const app = require("express")();
mongoose
.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(console.log(`connected to ${dbURI}`));
//----------------------------------------------------------------------
const departmentSchema = new Schema({ name: String, location: String });
const Department = model("department", departmentSchema);
const EmployeeSchema = new Schema({
firstName: String,
lastName: String,
department: { type: mongoose.Types.ObjectId, ref: "department" }
});
const Employee = model("employee", EmployeeSchema);
app.use("/", async (req, res) => {
// await Department.remove({});
// await Department.create({
// name: "Fiocruz",
// location: "Presidência"
// }).then(console.log(`we are good`));
// await Department.create({
// name: "IASI",
// location: "Roma"
// }).then(console.log(`we are good`));
// await Employee.create({
// firstName: "Jorge",
// lastName: "Pires",
// department: await Department.findOne({ name: "Fiocruz" })
// });
// await Employee.create({
// firstName: "Marcelo",
// lastName: "Pires",
// department: await Department.findOne({ name: "IASI" })
// });
// Employee.findOne("")
// .populate("department", "name")
// .select("department")
// .then(result => {
// console.log(result);
// });
await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" }, (err, result) => {
console.log(result);
})
.populate("department", "name")
.select("department");
res.json({
departments: await Department.find(),
employees: await Employee.find(),
employeesWithDep: await Employee.find().populate("department", "name"),
justDepartment: await Employee.findOne({ _id: "5e6e28ec480a9d32fc78c46b" })
.populate("department", "name")
.select("department")
});
});
app.listen(3000, () => {
console.log("we are on port 3000");
});

Mongoose populate not working for nested object

Client.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const clientSchema = new mongoose.Schema(
{
name: { type: String, required: true, default: "" },
}, {
timestamps: true
}
);
module.exports = mongoose.model("Client", clientSchema);
User.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const userSchema = new mongoose.Schema({
name: { type: String, required: true, default: "" },
clients: [{
client: {
type: Schema.Types.ObjectId,
ref: "Client",
default: null
},
user_group: {
type: Number
default: null
}
}]
}, { timestamps: true });
module.exports = mongoose.model("User", userSchema);
auth.js (Where trying to populate Clients)
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const Client = require("../models/Client");
router.post("/users", (req, res) => {
let params = req.body;
let total_client = [];
User.findOne({
email: params.email
})
.populate({
path: "clients.client",
model: Client
})
.exec((err, user) => {
console.log(user);
res.send(user);
});
});
module.exports = router;
Please check the above code. I have given code examples of my two models user.js and client.js. In user schema, I have referenced client inside an array object. While querying user, the client is not population. Please help me to get this thing done. Thanks in advance.
The following expects you to provide a name in the json body of your post request (your example uses email which does not exist in the user model). Also, your model is already defining the ref: Client and so you can simplify your request to just include the path clients.client.
router.post("/users", async (req, res) => {
const { name } = req.body;
const user = await User.findOne({ name: name }).populate('clients.client').exec();
res.send(user);
});
Solved this problem just adding an extra parameter in module export of client.js file
module.exports = mongoose.model("Client", clientSchema, "client");

Mongoose Model.findOne not a function

Having an issue with a model. Trying to do a model.findOne(), but I keep getting the error
TypeError: User.findOne is not a function
I have the model setup like so:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
firstName: String,
lastName: String,
emailAddress: {
type: String,
required: true,
unique: true
},
userName: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
module.export = User = mongoose.model("User", UserSchema);
and I have it imported in the file that I want to find a user:
const { Strategy, ExtractJwt } = require("passport-jwt");
const log = require("./logger");
require('dotenv').config();
const fs = require("fs");
const secret = process.env.SECRET || 'thisneedstob3ch#ng3D';
const mongoose = require("mongoose");
const User = require("./models/user");
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: secret
};
module.exports = passport => {
passport.use(
new Strategy(opts, (payload, done) => {
User.findOne({id: payload.id})
.then(user => {
if (user) {
return done(null, {
id: user.id,
name: user.name,
email: user.email
});
}
return done(null, false);
})
.catch(err => log.error(err));
})
);
};
Regardless, I get the error. I've tried .findById() as well as .findOne()
Is there something I'm missing?
You made a typo in you user.js file, you forgot the s of module.exports:
module.exports = User = mongoose.model("User", UserSchema);

Mongoose model.save() stuck pending?

I am using mongoose to handle my schemas, with MongoDB, but when trying to save a new entry to a collection the save() method appears to be stuck, neither the then() method or the catch() method of the promise appear to be called.
Does anyone have any ideas?
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// const Promise = require('bluebird');
const config = require('./config');
const UserSchema = new Schema({
email: { type: String, required: true, index: { unique: true } },
name: { type: String, required: false },
password: { type: String, required: true }
});
const User = mongoose.model('User', UserSchema);
console.log('config.database.url', config.database.url);
mongoose.Promise = global.Promise;
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.save();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
Environment: nodejs 8.9.0, node modules: Mongoose 4.13.6, mongodb 2.2.33
A little more experimenting and it would appear that I need to ensure the model is tied to the connection, such that:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// const Promise = require('bluebird');
const config = require('./config');
const UserSchema = new Schema({
email: { type: String, required: true, index: { unique: true } },
name: { type: String, required: false },
password: { type: String, required: true }
});
let User;
console.log('config.database.url', config.database.url);
mongoose.Promise = global.Promise;
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
// associate model with connection
User = connection.model('User', UserSchema);
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.save();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
Alternatively we should use the connect() method that will work with the model associated via mongoose.model.
For createConnection() can be used to create multiple connections, so using a 'global' model is not supported, from what I can tell.
Saying all this it would be nice if save() didn't simply block.
Note: In researching a refinement to my answer I came across the following: Queries hang when using mongoose.createConnection() vs mongoose.connect()

Resources