Mongoose Subdocument in another Invalid Schema error - javascript

I have 2 separate files, one encapsulates the Slot Schema, and another for the Location Schema. I'm trying to have a field in the Slot Schema that references the location Schema.
const mongoose = require('mongoose')
const locationSchema = require('./location')
const slotSchema = mongoose.Schema({
time: {
required: true,
type: String
},
typeOfSlot:{
required: true,
type: String
},
academic_mem_id:{
required: true,
default: null,
type: Number
},
course_id:{
required: true,
type: Number
},
location: [ locationSchema] // adjust
});
module.exports = mongoose.model('slots', slotSchema)
In a separate File:
const mongoose = require('mongoose')
const locationSchema = mongoose.Schema({
name:{
type:String,
required: true
},
capacity:{
type: Number,
required: true
},
type:{
type:String,
required:true
}
});
module.exports = mongoose.model('location', locationSchema)
I get this error when I run :
throw new TypeError('Invalid schema configuration: ' +
^
TypeError: Invalid schema configuration: `model` is not a valid type within the array `location`.
I'd really appreciate it if you'd help me figure out why the code above is wrong.
I want to export both the model and the Schema.

You are not exporting the locationSchema, but the location model. That is something entirely different and that is the reason you get the model is not a valid type within the array error.
Export only the schema and create/export the model in a separate file, e.g. locationModel.
const mongoose = require('mongoose')
const { Schema } = mongoose;
const locationSchema = new Schema({
name:{
type:String,
required: true
},
capacity:{
type: Number,
required: true
},
type:{
type:String,
required:true
}
});
module.exports = locationSchema;
Or if you want to keep both in the same file and export both:
module.exports = {
locationSchema,
locationModel,
};
And import them like so:
const { locationSchema, locationModel } = require('path/to/location.js');

That's wrong way referencing to other models.
First, you don't need require locationSchema, you can refer to that module in Schema. In your Slot Schema write this instead of your location field
location: {
type: mongoose.Schema.ObjectId,
ref: "location"
}

Related

Add a new field to every document from my mongo DB collection via mongoose

This question was asked several times, but despite that, I wasn't able to solve my problem. In my mongoose collection, I store 30 users with the following mongoose schema. I want to implement a newsletter on my site, therefore I want to add the new field:
newsletter: {
type: Boolean,
default: true
},
My question is: How can I add newsletter false/true to every user?
I found that, but it didn't work.
User.updateMany({}, [{ $set: { newsletter: false }}])
My Schema:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
token: { type: String, required: true }
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
Adding to the schema "newsletter" does solve the problem for new users, but doesn't add the field to the already existing ones.

How to populate an array of model instances inside a subdocument? MongoDB Mongoose

I have a subdocument that is nested as an array. Inside that subdocument I have references to other models. Using the .Find and .Populate methods I can receive the entire objects for single models referenced in the subdocument (check out Stop below) but not an array of model instances, Facts/Recommendations. For Facts/Recommendations I receive an array of object _ids. I can probably just take those _ids and make another query but this seems messy.
Is there a way to populate the array? Do I need to use Aggregate + $lookup? Is there a more Mongo way to restructure the Schema to simplify this?
Thank you for all and any help!
My subdocument called TourStop:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const TourStopSchema = new Schema({
stop: {
type: Schema.Types.ObjectId,
ref: 'Stop',
required:[true, 'must have a Stop'],
},
mandatory: {
type:Boolean,
default: false
},
check_in_time: {
type: Number,
default: 0
},
order: {
type:Number,
required: [true, 'Must have an order']
},
facts: [{
type: Schema.Types.ObjectId,
ref: 'Fact'
}],
recommendations: [{
type: Schema.Types.ObjectId,
ref: 'Recommendation'
}]
});
module.exports = TourStopSchema;
TourStops lives inside of Tour:
const mongoose = require('mongoose');
const TourStopSchema = require('../subdocs/tour_stop');
const Schema = mongoose.Schema;
const tourSchema = new Schema({
name: {
type:String,
required:[true,'Name is required!'],
unique: true
},
city: {
type: String,
required: [true, 'City is required!']
},
tourStops:[TourStopSchema]
});
const Tour = mongoose.model('Tour', tourSchema);
module.exports = Tour;
Stop Schema which is populated just fine.
const mongoose = require('mongoose');
const LocationSchema = require('../subdocs/location');
const ImageSchema = require('../subdocs/image');
const Schema = mongoose.Schema;
const stopSchema = new Schema({
name:{
type: String,
required:[true,'Must have a name!']
},
location:LocationSchema,
categories: {
type: [String],
default:[]
},
images:{
type:[ImageSchema],
default:[]
}
});
const Stop = mongoose.model('Stop', stopSchema);
module.exports = Stop;
And Fact Schema which is not populated correctly, instead returns an array of strings with the _ids
Fact:
const mongoose = require('mongoose');
const ImageSchema = require('../subdocs/image');
const Schema = mongoose.Schema;
const factSchema = new Schema({
stop: {
type: Schema.Types.ObjectId,
ref:'Stop',
required:[true, 'A Fact must have a Stop!'],
},
description: {
type: String,
required: [true,'A Fact must have a description!']
},
images: {
type:[ImageSchema],
default:[]
}
});
const Fact = mongoose.model('Fact', factSchema);
module.exports = Fact;
And I'm running a test to check that the schema is properly hooked up to retrieve all the attributes of a TourStop:
it('saves a full relation graph', (done) => {
User.findOne({ first_name: 'Dean' })
.populate({
// in that user find the tours property and load up all tours
path: 'tours',
// inside of all those tours, find the tourstops property and load all associated stops
populate: {
path: 'tour_stops.facts',
model: 'Fact'
},
populate: {
path: 'tour_stops.stop',
model: 'Stop'
}
})
// .populate('tours.tour_stops[0].facts')
.then((user) => {
// console.log(user.tours[0].tour_stops[0].stop);
console.log(user.tours[0].tour_stops[0]);
// console.log(Array.isArray(user.tours[0].tour_stops[0].facts))
assert(user.first_name === 'Dean' );
assert(user.tours.length === 1);
assert(user.tours[0].name === "Awesome New Tour");
assert(user.tours[0].tour_stops[0].stop.name === 'Jaffa Clock Tower');
// assert(user.tours[0])
// assert(user.blogPosts[0].title === 'JS is Great');
// assert(user.blogPosts[0].comments[0].content === 'Congrats on great post!' );
// assert(user.blogPosts[0].comments[0].user.name === 'Joe' )
done();
})
})
You can use the following code to populate tours, stop, facts and recommendations.
Note in model property, we should not give string value, but the model itself. So you need to import them to your code.
User.findOne({ first_name: "Dean" })
.populate({
path: "tours",
populate: {
path: "tourStops.stop",
model: Stop
}
})
.populate({
path: "tours",
populate: {
path: "tourStops.facts",
model: Fact
}
})
.populate({
path: "tours",
populate: {
path: "tourStops.recommendations",
model: Recommendation
}
})
.then(user => {
console.log(user);
});

How do I find if an Id is present in the array of team members (which stores user ids)?

I have this model of workspace schema in my node js project(model is displayed below)
After the user logs into my application I want to display the information of a workspace only if it is created by him or he is a team member of that workspace
I am able to find the workspaces created by the user by the following query
Workspace.find({creator:req.user._id},function(err,workspaces){
res.render('home',{
wokspacses:workspaces
});
});
similarly, I also want the workspaces in which the user is the team member
Workspace.find({creator:req.user._id},function(err,workspaces){
Workspace.find({team_member:"WHAT SHOULD I WRITE HERE"},function(err,workspaces2){
res.render('home',{
wokspacses:workspaces
wokspacses2:workspaces2
});
});
Since team_members is an array simply passing the user id is not yielding the result and workspaces2 remains empty
Thank you for your time !!
const mongoose = require('mongoose');
const workspaceSchema = mongoose.Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
module.exports = mongoose.model('Workspace',workspaceSchema);
Use the $in Operator.
const mongoose = require("mongoose")
const Schema = mongoose.Schema
mongoose.connect('mongodb://localhost/stackoverflow', {useNewUrlParser: true});
const workspaceSchema = new Schema({
name:{
type:String,
required:true
},
date: {
type: Date,
required: true
},
creator:{
type: Object,
ref: 'User',
required: true
},
team_member: [{ type: Object, ref: 'User' }]
});
const WorkspaceModel = mongoose.model('Workspace',workspaceSchema);
const sessionUserId = "5d330f3de87ec83f95504c44" //i.e. req.user._id;
WorkspaceModel.find({
$or:[
{ creator: sessionUserId },
{
team_member: {
$in: [sessionUserId]
}
}
]
}).exec((err, result) => {
console.log("result", result)
})

Can you search other models with instance methods in Mongoose?

When do models receive their prototype?
I know that embedding is generally the answer here, but I have a special case.
If I call to another model in an instance's custom method, it seems to fail.
The error I'm getting:
Fish.find is not a function at model.UserSchema.methods.fishes
The Fish model is made into a model:
// Require mongoose to create a model.
var mongoose = require('mongoose'),
User = require('./user.js');
// Create a schema of your model
var fishSchema = new mongoose.Schema({
name: String,
category: String,
user: { type: mongoose.Schema.Types.ObjectId, ref:'User' }
});
// Create the model using your schema.
var Fish = mongoose.model('Fish', fishSchema);
// Export the model of the Fish.
module.exports = Fish;
The User model calls to the Fish model within the fishes custom instance method:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
Fish = require('./fish');
//||||||||||||||||||||||||||--
// CREATE USER SCHEMA
//||||||||||||||||||||||||||--
var UserSchema = new Schema({
name: { type: String, required: true },
phoneNumber: {
type: String,
required: true,
index: { unique: true },
minlength: 7,
maxlength: 10
},
password: { type: String, required: true, select: false }
});
// … some bcrypt stuff…
// Access user's fishes - THIS IS WHAT'S MESSING UP!!
UserSchema.methods.fishes = function(callback) {
Fish.find({user: this._id}, function(err, fishes) {
callback(err, fishes);
});
};
module.exports = mongoose.model('User', UserSchema);
When I call .fishes() in my seeds, it claims that Fish.find is not a function.
Why!? Any help would be greatly appreciated!
The issue is a circular import (fish.js requires user.js that requires fish.js, etc).
You can work around that by resolving the model class at runtime:
UserSchema.methods.fishes = function(callback) {
mongoose.model('Fish').find({user: this._id}, function(err, fishes) {
callback(err, fishes);
});
};

Mongoose Schema registration - passing config info

What's a good way to pass configuration information while registering mongoose schemas and using them?
Say in the below example, I want to make the read preference and timeout value come from a config file... "read: ['nearest']}, safe: {wtimeout: 10000})"
something like => "read: [dbConfig.readPrefence]}, safe: {wtimeout: dbConfig.writeTimoutMS})", what's a good way to pass dbConfig?
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var blogSchema = new Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
}, {read: ['nearest']}, safe: {wtimeout: 10000}));
The solution may depend on how you've organized your files, meaning what you might be asking is how to pass around a configuration to multiple files which each contain a schema. But first looking at the simple case, a single schema exists within this file, I would recommend loading the configuration from there and pass in the values.
config.json
{
"read": "nearest",
"safe": true
}
my-schema.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
config = require('./config.json');
var blogSchema = new Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
}, {
read: config.read,
safe: config.safe
});
If you have multiple schemas and you'd rather load the configuration only once and pass that around, then I'd recommend sending it within the require call of the schema file. For example:
app.js
var mySchema = require("./my-schema.js")(config);
my-schema.js
module.exports = function(config) { ... }

Categories

Resources