Mongoose reference on custom string _id - javascript

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);

Related

How to create a foreign key in MongoDB with Mongoose?

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.

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 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.

Connect mongoose-array-values to a unique ID

This may seem like a vague question, but I'm going to try to explain the best I can. As a side note, I'm quite new to using mongoose :)
I have a mongoose-schema storing different values for each user, like so...
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: String, required: false }],
});
The "files"-key contains an array of values, lets say for example:
userSchema.files = [value1, value2, value3]
And I want each value to be connected to some kind of ID, so that when I call the specified ID, I get the specified value. Just for demonstrating purposes, it could look something like this:
userSchema.files = [{value:value1, id: id1},
{value:value2, id: id2},
{value:value3, id: id3}]
Then I want to find the specified id, and return it's "value"-key in a request:
router.route("/home/:id")
.get(restrict, function(req, res) {
User.findOne({ user: req.session.Auth.username }, function(error, data) {
data.files.forEach(function(file) {
if (file.id === req.params.id) {
response.render("../home", file.value)
}
}
});
});
How can I do this? Tried pushing an object to files, but that didn't work as expected. Read something about ObjectId, but couldn't quite understand it. Any tips?
I think you simply need to create a separate model for File and connect it to your User model using the 'ref' keyword :
let fileSchema = mongoose.Schema({
_id : Number,
value : String
});
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: Number, ref: 'File' }]
});
let User = mongoose.model('User', userSchema);
let File = mongoose.model('File', fileSchema);
let f1 = new File({ _id: 1, value: 'File 1'});
let f2 = new File({ _id: 2, value: 'File 2'});
let f3 = new File({ _id: 3, value: 'File 3'});
let user1 = new User({user:'chuck', pass:'norris'});
user1.files.push(f1);
user1.files.push(f2);
user1.files.push(f3);
user1.save(function(err){ });
Now to get the data back:
User
.findOne({ user: 'chuck' })
.populate('files') // only works if we pushed refs to children
.exec(function (err, user) {
if (err) return handleError(err);
console.log(user);
//you can now loop through user.files and compare _id
user.files.forEach(function(file) {
if (file._id === req.params.id) {
response.render("../home", file.value)
}
}
});
You can read about mongoose reference population here: http://mongoosejs.com/docs/populate.html

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