How to create a foreign key in MongoDB with Mongoose? - javascript

I've a simple "table" user, where each user has a username, an email and a password. Into users.js:
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
},
{ collection: 'users' }
)
const model = mongoose.model('UserSchema', UserSchema)
module.exports = model
Now, I want to define an account. One user can have one or more bank account. For example, I can have account_1 with a balance of 100$, account_2 with a balance of 200$ and so on. The problem is that the collection accounts, has two parameters: one is the user (and this is a foreign key, because it's the user nickname in the collection users), and the other one is the balance (a simple number). Into accounts.js:
const mongoose = require('mongoose')
const AccountSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
balance: { type: Number, required: true},
},
{ collection: 'accounts' }
)
const model = mongoose.model('AccountSchema', AccountSchema)
module.exports = model
How can I say that the username into AccountSchema is the field of UserSchema?

You use refs in mongoose.
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const AccountSchema = new mongoose.Schema(
{
username: { type: Schema.Types.ObjectId, required: true, ref: "user },
balance: { type: Number, required: true},
},
{ collection: 'accounts' }
)
const model = mongoose.model('AccountSchema', AccountSchema)
Note: The ref should be the name you passed as the first parameter to the mongoose.model function in your users model.

Related

Cannot read properties of undefined reading ("users") in schema for mongodb . this code was working the last few days

connection api
import mongoose from "mongoose";
const MONGODB_URL = NEXT_MONGO_URL
if (!MONGODB_URL) {
throw new Error(error);
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = {
conn: null,
promise: null,
};
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(MONGODB_URL, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
user api
__________________________________________________________________________
var mongoose = require("mongoose");
const userSchema = new mongoose.Schema(
{
firstName: { type: String, required: true, maxlength: 256 },
lastName: { type: String, required: true, maxlength: 256 },
username: {
type: String,
lowercase: true,
unique: true,
required: [true, "can't be blank"],
match: [/^[a-zA-Z0-9]+$/, "is invalid"],
index: true,
},
password: { type: String, required: true, maxlength: 256 },
age: { type: Number },
email: {
type: String,
lowercase: true,
unique: true,
required: [true, "can't be blank"],
match: [/\S+#\S+\.\S+/, "is invalid"],
index: true,
},
},
{ timestamp: true }
);
const Users = mongoose.models.users || mongoose.model("users", userSchema);
export default Users;
I tried deleting and recreating the user part of the db and even rewriting the schema.
I currently have the same code working for my blog posts part of the db, so I don't think its the connection api
any help would be appreciated, please explain it like you would to a 10 year old
Ive been learning to code for a few month. thank you
Try and understand what the error message is saying: you're trying to access a property users on something that's undefined.
So that suggests that mongoose.models is undefined, because that's where you're trying to access that users property.
Since mongoose.models isn't even documented, I would suggest not using it and just use documented methods of retrieving a model:
const Users = mongoose.model("users", userSchema);

Mongoose reference on custom string _id

I created a schema with a custom _id (an example: PIy8CvtO32a0DOvXv) using a function that generates a random string. I can create and edit my documents perfectly.
Then, I tried referencing a document of this schema in another one but i keep getting this error integration references a non existing ID when i try to create a document in this collection. This error pops normally when the the provided _id doesn't match any document in your collection but I checked and found a document with this _id. Is there something i'm missing out or is there any restriction related to my custom string _id ?
Below is my code:
const mongoose = require('mongoose');
const { ObjectID } = require('mongodb');
const idValidator = require('mongoose-id-validator');
const integrationSchema = mongoose.Schema(
{
_id: {
type: String,
required: true,
unique: true,
},
name: {
type: String,
required: true,
},
provider: {
type: String,
required: true,
},
active: {
type: Boolean,
required: true,
}
})
integrationSchema.plugin(idValidator);
const IntegrationSchema = mongoose.model('Integration', integrationSchema);
const mongoose = require('mongoose');
const { ObjectID } = require('mongodb');
const idValidator = require('mongoose-id-validator');
const sourceSchema = mongoose.Schema({
integration: {
type: String,
required: true,
ref: 'Integration',
refConditions: {
active: true,
},
},
type: {
type: String,
required: true,
},
});
sourceSchema.plugin(idValidator);
const SourceSchema = mongoose.model('Source', sourceSchema);

Mongoose populating

i am a quite new to mongoose and mongodb and have been trying to connect my user with a bunch of image posts. I read a lot about mongoose populate but i keep on getting empty images [].
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
images: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Image'
}
]
});
module.exports = mongoose.model('User', userSchema);
const mongoose = require('mongoose');
const imageSchema = new mongoose.Schema({
id: mongoose.Schema.Types.ObjectId,
image: {
type: String,
required: true
},
description: {
type: String,
required: true
},
})
module.exports = mongoose.model('Image', imageSchema);
const getOne = async (userId) => {
let lastTenImages = await User.findById(userId).populate('images').lean();
console.log(lastTenImages.images);
// return lastTenImages
}
I also used mongoose.Types.ObjectId instead of Schema but still got the same result- an empty array
In my opinion you should discard the id portion which is not working as the link to the User model. In other words try something like:
const imageSchema = new mongoose.Schema({
image: {
type: String,
required: true
},
description: {
type: String,
required: true
},
})
I think that should populate the right array.
In addition, when you get the value you will be getting an array of objects. So you would need to map over it. lastTenImages.images won't produce anything.

Nested JSON object not saving to database MongoDB

I have three mongo schemas, each nest into one another. The main one has a nested JSON, which also has a nested JSON inside that. However, when the User is saved using the main Schema, the other two nested schemas aren't being saved with their default values, why? Here's an example of my three schemas (just an example data structure):
const userContacts = new mongoose.Schema({
user1PhoneNumber: {
type: Number,
default: 0
},
user2PhoneNumber: {
type: Number,
default: 0
}
})
const contact = new mongoose.Schema({
phoneNumber: {
type: Number,
default: 0
},
contacts: {
type: userContacts
}
})
const finalUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
max: 255
},
email: {
type: String,
required: true,
max: 255,
},
password: {
type: String,
required: true,
min: 10,
max: 1024,
},
contactDetails: {
type: contact
}
})
module.exports = mongoose.model('User', finalUserSchema);
When the user is first created using the mongoose model, the values aren't set as they will be used later on...but they should still appear in the database with their default values:
const user = new User({
username: req.body.username,
email: req.body.email,
password: hashedPassword,
});
What gets saved in the database:
Where is the contactDetials nested JSON object with it's default values, I shouldn't have to provide any data when I first save the user as it should just use the data model with its default values?
May you should try this:
contactDetails: contact
instead of:
contactDetails: {type: contact}
same for Contacts

How to save document based on user id using mongoose?

I am trying to save template based on user id , How can i make sure when template save it save with user id _id ? i added reference to the templateSchema for User.
user.model.js
var UserSchema = new mongoose.Schema({
_id: { type: String, required: true, index: {unique: true}},
firstName: String,
lastName: String,
type: String,
groups:[{type: String, ref: 'Group', required: false}]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
});
export default mongoose.model('User', UserSchema);
template.model.js
var User = require('../user/user.model.js');
var TemplateSchema = new mongoose.Schema({
_id: { type: String, required: true},
name: String,
id: String,
appliesTo: [],
properties: [],
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
export default mongoose.model('Templates', TemplateSchema);
template.controller.js
var eTemplate = require('./template.model');
export function create(req, res) {
console.log(req.body);
eTemplate.createAsync(req.body)
.then(responseWithResult(res, 201))
.catch(handleError(res));
}
Mongoose has two built-in functions that are called before (pre) and after (post) you save a document. My advice is to make use of them. Here is an example of my code in which I search for an sequence number before saving the user document. You can do the same: When you save the template, make a request for the user id to the database (Or vice-versa). You can even save one, get the id and save the other.
Bellow follows my code for the sequence and the user.
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
id: { type: String },
...
});
UserSchema.pre('save', function(next) {
let doc = this;
let id = 'userSeq'
Sequence.findByIdAndUpdate(id, { $inc : {nextSId : 1} }, function(error,data) {
if(error)
next(error)
doc.id = data.nextSId-1;
next();
})
});
I hope my answer was useful for you. Just a remark, pre and post are not called in the event of updates for the document.

Categories