Field with ref as parameter in find doesn't work - node.js

I've got these two Schemas:
const BookSchema = new Schema({
name: { type: String, required: true },
author: [{ type: String }],
category: [{ type: String }],
store: { type:mongoose.Schema.Types.ObjectId, ref: 'Store'}
});
module.exports = mongoose.model('Book', BookSchema);
const storeSchema = new Schema({
name: { type: String, required: true },
slug: { type: String, index: true, required: true, unique: true}
});
module.exports = mongoose.model('Store', StoreSchema);
i'm trying to get the Books from a Store, described as follows:
exports.getBooksFromStore = async(idStore) => {
const data = await Book.find({store : idStore});
return data;
}
But, the find() written that way doesn't work.

The issue appears to be the expectation for the find method to return a promise object when it actually returns a query object. In the exampled code provided, the value assigned to data is the query object returned from the find method and not the intended promise object from the execution of the query.
To execute the query and return the promise object for it, the query exec method will need to be called.
exports.getBooksFromStore = async (idStore) => {
// const data = await Book.find({store : idStore});
const data = await Book.find({store : idStore}).exec();
return data;
};

Related

Referencing a document from another database in mongoose?

How can I reference a document from another database?
This is how I'm connecting to the databases as mentioned in the docs (Docs):
import mongoose from "mongoose";
export default async function connect() {
const usersConn = await mongoose
.createConnection(process.env.USERS_MONGO_URI)
.asPromise(); // Wait for the connection to be created
const videosConn = await mongoose
.createConnection(process.env.VIDEOS_MONGO_URI)
.asPromise(); // Wait for the connection to be created
const User = usersConn.model(
"User",
new mongoose.Schema({
id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
})
);
const Video = videosConn.model(
"Video",
new mongoose.Schema({
title: {
type: String,
required: true,
},
path: {
type: String,
required: true,
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
})
);
return {
usersClient: usersConn.getClient(), // For next-auth
User,
Video,
};
}
But when I try to populate my query:
const video = await Video.findById(
new mongoose.Types.ObjectId(id as unknown as string)
)
.populate("author")
.exec((err, v) => {
console.log(err, v);
});
It gives me the following error:
MissingSchemaError: Schema hasn't been registered for model "User".
Use mongoose.model(name, schema)
I've been trying to look for this for a long time, but I'm unable to find an answer. The way I solved this, although a bit hacky, is by saving the id in a field called author_id, then searching through the User model for the id when querying.

Mongoose Virtual Referencing Other Model/Collection

Trying to reference one collection in mongo via another model's virtual. Currently the only output I'm getting is 'undefined'. Was able to execute this in my main js file as a standalone query but can't figure out how to get this to function as a virtual. Help appreciated.
const mongoose = require('mongoose');
const { stylesList } = require('../styles.js')
const Schema = mongoose.Schema;
const Post = require('./post')
const options = { toJSON: { virtuals: true } };
// options object for the schema, passed in after the actual schema.
const BrandSchema = new Schema({
name: {
type: String,
unique: true,
required: true
},
linkedBrands: [String],
styles: [{ type: String, enum: stylesList }],
links: {
homepage: {
type: String,
required: true
},
grailed: {
type: String,
required: true
},
wikipedia: String
},
bannerImage: String,
likes: {
type: Number,
default: 0
}
}, options);
BrandSchema.set('toObject', { getters: true });
BrandSchema.virtual('amountWorn').get(async function() {
const wornPosts = await Post.find({includedBrands: this._id});
return wornPosts.length
});
module.exports = mongoose.model('Brand', BrandSchema)

Mongoose find Object where query contains an array of objects based on the ObjectId

I would like to query a model with an array of objects in a async function.
My ContractSchema:
const ContractSchema = new mongoose.Schema({
Nr: {
type: String,
trim: true,
sparse: true,
},
});
My StationSchema
const StationSchema = new mongoose.Schema({
ContractId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Contract',
required: true,
},
Name: {
type: String,
trim: true,
},
});
My first query works, as a result I am getting two objects:
const contract = await Contract.find({ Nr: 'pi' });
My second query, as a result I should get 2 objects. But I am getting a lot of objects where ContractId is NULL.
const station = await Station.find({ ContractId: { $in: contract._id } });
For a test I changed the second query, and I am getting the two results:
const station = await Station.find({ ContractId: { $in: ['...9b', '...b4'] } });
For my second query I would like to get teh two result without any NULL value, how do I? What should this query look like?

UnhandledPromiseRejectionWarning: TypeError: place.toObject is not a function

Here I am trying to fetch Users Created places using userId. Here are User model and places model and in Controller, I have writing logic to fetch places by userId. Unfortunately, I am getting error "UnhandledPromiseRejectionWarning: TypeError: place.toObject is not a function" during sending response in res.json({ }) method.
Place Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const placeSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
image: { type: String, required: true },
address: { type: String, required: true },
location: {
lat: { type: Number, required: true },
lng: { type: Number, required: true },
},
creator: { type: mongoose.Types.ObjectId, required: true, ref: 'User'}
});
module.exports = mongoose.model('placemodels', placeSchema);
User Model
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, minlength: 6 },
image: { type: String, required: true },
places: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Place'}]
});
userSchema.plugin(uniqueValidator);
module.exports = mongoose.model('usermodels', userSchema);
Controller
const getPlacesByUserId = async (req, res, next) => {
const userId = req.params.uid;
let userWithPlaces;
try {
userWithPlaces = await User.findById(userId).populate('placemodels');
} catch (err) {
console.log(err);
const error = new HttpError(
'Fetching places failed, please try again later',
500
);
return next(error);
}
// if (!places || places.length === 0) {
if (!userWithPlaces || userWithPlaces.places.length === 0) {
return next(
new HttpError('Could not find places for the provided user id.', 404)
);
}
res.json({
places: userWithPlaces.places.map(place =>
place.toObject({ getters: true })
)
});
};
The references are really important in mongoose populate. In the schema, the refs refer to the mongoose name of the schema. Since the names are: 'placemodels' and 'usermodels'. The refs fields should use the exact name.
Reference: https://mongoosejs.com/docs/api.html#schematype_SchemaType-ref
The second important part is the parameters of the populate methods. The documentation specifies that the first argument of the populate function is a name path and is an object or a string. In the case above a string is used. It should refer to the name field to populate.
This means that the code should be the following because we want to populate the places field. The schema is responsible to know from where to get the information
...
userWithPlaces = await User.findById(userId).populate('places');
...
References: https://mongoosejs.com/docs/api.html#query_Query-populate
The references are really important in mongoose populate. In the schema, the refs refer to the mongoose name of the schema. Since the names are: 'placemodels' and 'usermodels'. The refs fields should use the exact name.
Reference: https://mongoosejs.com/docs/api.html#schematype_SchemaType-ref
The second important part is the parameters of the populate methods. The documentation specifies that the first argument of the populate function is a name path and is an object or a string. In the case above a string is used. It should refer to the name field to populate.
This means that the code should be the following because we want to populate the places field. The schema is responsible to know from where to get the information

Search by ObjectId in mongoose schema nodejs

I am using mongoose with nodejs . I have item schema and user schema given below.
var userSchema = new Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
items : [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
var itemSchema = new Schema({
name: { type: String, required: true },
_owner : { type: Schema.Types.ObjectId, ref: 'User' }
});
I am trying to find item by user id(_owner in item schema).
I have tried to find directly
var uid = req.decoded._id;
var item = Item.findOne({"_owner": uid});
console.log(item.name); // undefined
By searching similar I found that id needs to be in ObjectId object so I tried
var uid = new mongoose.Types.ObjectId(req.decoded._id);
var item = Item.findOne({"_owner": uid});
console.log(item.name); // undefined
In both the cases item.name is undefined .Note that I have rechecked the value of req.decoded._id(by printing) with the db so it not undefined and present in db.
Is there anything I am doing wrong?
Model.findOne is an async call. It doesn't return the doc, it passes it to a callback function that you need to provide as a second parameter.
var uid = req.decoded._id;
var item = Item.findOne({"_owner": uid}, function(err, item) {
console.log(item.name);
});

Resources