Here is my problem I have two schemas one nested in another as an array. I am trying to push into the array and save the subdocument but it is not saving properly, I get an object that is saved but none of the fields are saved except for its _id. Do I have to save each model individually first? What is the issue here?
Here are my two schemas:
import mongoose from "mongoose";
import {contactSchema} from "./ContactSchema"
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{ contactSchema }],
}
});
export default mongoose.model("Big", bigSchema);
import mongoose from "mongoose";
export const contactSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
age: {
type: number,
required: false,
}
});
export default mongoose.model("Contact", contactSchema);
Here is my code that I use to push to the array of contacts.
public async saveContact(
testField: string,
name: string,
age: number,
) {
const newContact = new Contact({
name: name,
age: age,
});
console.log(newContact);
return UserContacts.findOneAndUpdate(
{
testField: testField,
},
{ $push: { contacts: newContact } },
{ new: true, upsert: true }
);
}
However when I check my database, this is what I see instead. There is an objectId but not what I expect to see, which is a list of Contact subdocuments inside my "Big" document
{
"_id" : ObjectId("XXXX"),
"testField" : "XXXXX",
"contacts" : [
{
"_id" : ObjectId("XXXXX")
}
],
"__v" : 0
}
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{ contactSchema }],
}
});
should be:
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [contactSchema],
}
});
Try that and see what happens.
Edit: Also, if you intend for contacts to be an array of references to the Contact model, then you need to do this instead:
export const bigSchema = new mongoose.Schema({
testField: {
type: String,
required: true,
},
contacts: [{type: mongoose.Schema.Types.ObjectId, ref: 'Contact'}],
}
});}
This will make contacts an array of Contact IDs, so you're not duplicating any data, but just referencing the contacts in their collection. docs
Related
I have a collection called Orders that contains this schema:
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
restaurant: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Restaurant',
required: true
},
dishes: [
{
dish: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
},
amount: Number
}
],
price: {
type: Number,
required: true
},
comment: {
type: String,
required: false
},
status: {
type: String,
enum: ['PROCESSING', 'CANCELLED', 'COMPLETED', 'ERROR'],
default: 'PROCESSING'
},
timestamp: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema);
Inside my router, I have this code:
let orders = await Order.find({restaurant: restaurantID, status:'PROCESSING'}).populate('dishes._id').exec()
Order.find does not throw an exception, but it isnt working either.
I want the res.body to look like this:
{
"_id": "objectID",
"user": "objectID",
"restaurant": "objectID",
"dishes": [
{
"amount": number,
"dish": {
//dish object
}
},
...
],
//other order properties
},
...
]
But for some reason the dishes array looks like this:
"dishes": [
{
"amount": 1,
"_id": "6184e848e6d1974a0569783d"
}
],
What am I doing wrong?
I know that if populate() worked the res.body dishes array would not have a property called 'dish' and instead have a property called _id that would contain the dish object, but this shouldnt be hard to change once populate() works.
EDIT:
I realised that my createOrder route could be part of the problem since it ignores my schema and uses an id property for the objectID instead of dish. The array I save to the DB contains a property called id for the id instead of dish, but shouldnt my schema throw an exception when i try to save something like this to my database?
At first glance, I think the problem might be that you have a syntax problem.
Try
.populate('dishes').exec()
instead of
.populate('dishes._id').exec()
I'm trying to filter my pets by category, I have the following model of pets:
const Pet = mongoose.model(
'Pet',
new Schema({
name: {
type: String,
required: true,
},
age: {
type: Number,
required: true,
},
description: {
type: String,
},
weight: {
type: Number,
required: true,
},
color: {
type: String,
required: true,
},
images: {
type: Array,
required: true,
},
available: {
type: Boolean,
},
category: Object,
user: Object,
adopter: Object,
}, { timestamps: true }),
);
module.exports = Pet;
when I try to get the data through postman it returns an empty array as a response.
my code to filter by category:
static async getByCategory(req, res) {
const id = req.params.id;
// check if id is valid
if (!ObjectId.isValid(id)) {
res.status(422).json({ msg: 'Invalid ID' });
return;
}
const pets = await Pet.find({ 'category._id': id }).sort('-createdAt');
if (!pets) {
res.status(404).json({ msg: 'Pets not found!' });
return;
}
res.status(200).json({ pets });
}
it's my first time using mongodb so i'm not sure what's wrong.
id being passed from the client side is string and the one which is saved in the db is ObjectId. Convert the string to Mongoose ObjectId before Pet.find().
const id = mongoose.Types.ObjectId(req.params.id);
const pets = await Pet.find({ 'category._id': id }).sort('-createdAt');
Don't forget to import 'mongoose'.
Could you check that your MongoDB indeed has a field category._id?
I have an array of objectIDs references in mongo. I want to get a specific element in that array after populating the objectIDs. the problem is i get an empty array.
Here's my schema
// Patient Schema - start
const patientSchema = new mongoose.Schema({
nom: {
type: String,
required:true
},
prénom: {
type: String,
required:true
},
naissance:{
type:Date,
},
adresse: {
type: String,
required:true
},
téléphone: {
type: String,
required:true
},
profession: {
type: String,
},
/// the field i'm trying to populate
consultations:[{
type: mongoose.Schema.Types.ObjectId,
ref:'Consultation'
}],
salle:{
type: mongoose.Schema.Types.ObjectId,
required: true,
ref:'Salle'
},
date:{
type:String,
default: Date.now
},
jointes: {
type:Array
},
questionnaire: {
type:Object
},
}, { collection : 'patients'} );
const patients = mongoose.model('Patient', patientSchema);
Consultation schema
const consultationSchema = new mongoose.Schema({
date: {
type: String,
required:true
},
motif:{
type: String,
},
observations: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Observation"
}],
paiements: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Paiement"
}],
ordonnances: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Ordonnance"
}]
});
const consultations = mongoose.model('Consultation', consultationSchema);
the exports
module.exports = {
patients: patients,
consultations: consultations,
}
The router where i'm trying to populaet consultation field and then get the item
const {patients} = require('./patient.models')
const {consultations} = require('./patient.models')
// not working , getting empty array
const patient = await patients.find({"consultations.motif" : "Checking"}).populate('consultations')
res.send(patient)
The mongo db record , to show you that the field does exist
Here's what i get when i do make the following query iwthout specifiying the field
const patient = await patients.find().populate('consultations')
res.send(patient)
This question already has been answered here: Find after populate mongoose
Here is the solution for your case which does not involve changing the database structure:
const patient = await patients.find().populate({
path: 'consultations',
match: {
motif: 'Checking'
}
})
res.send(patient)
I have 2 schemas:
const mongoose = require('mongoose');
const PinSchema = new mongoose.Schema({
title: String,
content: String,
image: String,
latitude: Number,
longitude: Number,
author: {
type: mongoose.Schema.ObjectId,
ref: "User"
},
comments: [
{
text: String,
createdAt: {
type: Date,
default: Date.now,
author: {
type: mongoose.Schema.ObjectId,
ref: "User"
}
}
}
]
}, { timestamps: true });
module.exports = mongoose.model("Pin", PinSchema);
and
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: String,
email: String,
picture: String
});
module.exports = mongoose.model("User", UserSchema);
As you can see author field in Pin is the same as the _id in User schema.
I then try to populate the comments author field in the Pin schema like this:
const pinUpdated = await Pin.findOneAndUpdate(
{ _id: pinId },
{ $push: { comments: "some comment" } },
{ new: true }
).populate("author")
.populate("comments.author");
however the result object has author field set to null so population doesn't work.
I'm not against doing this with native mongo syntax using $lookup but in my case it's not just looking up an array it's looking up a field of an objects array:
db.pins.aggregate([
{
$lookup:
{
from: "users",
localField: "comments._id", // this won't work
foreignField: "_id",
as: "authorOutput"
}
}
])
what am I missing in populate()?
It looks like your author field in the comments array is nested inside the createdAt object, which is likely unintentional. Changing PinSchema to the following (closing curly brace before author) should fix it:
const PinSchema = new mongoose.Schema({
...
comments: [
{
text: String,
createdAt: {
type: Date,
default: Date.now,
},
author: {
type: mongoose.Schema.ObjectId,
ref: "User"
}
}
]
}, { timestamps: true });
These the response for user that Im getting from get request to profile API
"user": "5cc3a4e8d37a7259b45c97fe"
What I'm looking for instead is
"user":{
"_id": "5cc3a4e8d37a7259b45c97fe",
"name":"Jhon Doe",
}
Here is my code:
Profile.findOne({
user: req.user.id
})
.populate('user',['name']) // I added this line to populate user object with name
.then(profile=>{
if(!profile){
errors.noprofile = 'There is no profile for this user'
return res.status(404).json(errors);
}
res.json(profile)
})
.catch(err => res.status(404).json(err));
However, Im getting these error:
{
"message": "Schema hasn't been registered for model \"users\".\nUse mongoose.model(name, schema)",
"name": "MissingSchemaError"
}
What am I missing
Profile Schema
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Here is how my Users schema looks like
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
name:{
type: String,
required: true,
},
email:{
type: String,
required: true,
},
password:{
type: String,
required: true,
},
avator:{
type: String,
},
date:{
type: Date,
default: Date.now,
}
});
module.exports = User = mongoose.model('Users', UserSchema)
Schema that you are referencing in Profile schema is users, but you have saved your user schema as Users. So I would say that you need to update your Profile schema:
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'Users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Name under which is saved your User schema can be found in this line
module.exports = User = mongoose.model('Users', UserSchema)
The error says you don't have Schema for Users. You reference it from Profile Schema, but you don't have it. It can be this way:
const Users = new Schema({
name: String
})