I can't access 'title' on mongosh - getting undefine - node.js

//here is my schema
const mongoose = require ('mongoose');
const Schema = mongoose.Schema;
const ResortSchema = new Schema ({
title: String,
price: Number,
descriptor: String,
places: String,
location: String
});
var Resortdata = mongoose.model('holidayresorts', ResortSchema);
module.exports = Resortdata;
// index.js - where I tried to access 'places' and 'descriptors'
const sample = array => array[Math.floor(Math.random() * array.lenght)];
const seedDB = async () => {
await holidayresorts.deleteMany({});
for (i = 0; i < 5; i++){
const random5 = Math.floor(Math.random() * 5);
const Resort = new holidayresorts ({
location: `${cities[random5].city} , ${cities[random5].state}`,
title: `${sample(descriptor)} ${sample(places)}`
})
await Resort.save();
}
}
seedDB();
// what I am getting in on mongosh
{
_id: ObjectId("630cecf45a6457bfe74c0b9d"),
title: 'undefined undefined',
location: 'Owerri , Imo',
__v: 0
}
]
Please I need help, why am I getting 'undefined' for my title?
I think my Schema is correct
I can't really figure out what is wrong
I am thinking it is from my array
Please I need help
Have been stuck for days now
Help me

Related

Saving array of children of a Mongoose Schema and then adding returned IDs to parent

i'm trying to loop over an array of objects, saving them to MongoDB and then add the returned ObjectIds to a parent Schema which then is also saved. I'm at a loss here.
Everything gets saved correctly but the Recipe (parent) apparently is saved before I get the returned ObjectIds of the Tags (children). I feel like I've used the async and await keywords a bit to often.
Can someone help? Code simplified, but I can post more if needed.
Parent Schema:
const recipe = new mongoose.Schema(
{
name: String,
ingredients: [
{
type: mongoose.SchemaTypes.ObjectId,
ref: "Ingredient",
},
],
}
);
Child Schema:
const ingredientSchema = new mongoose.Schema({
value: String,
label: String,
});
Payload:
{
name: "Rezept",
ingredients: [
{
label: "zutat",
value: "Zutat",
},
{
label: "schokolade",
value: "Schokolade",
},
],
};
My router:
recipesRouter.post("/", async (req, res) => {
const { body } = req;
const saveIngredients = async () => {
let ingredientIDs = [];
body.ingredients.map(async (ingredient) => {
const i = new Ingredient({
value: ingredient.value,
label: ingredient.label,
});
const savedIngredient = await i.save();
ingredientIDs.push(savedIngredient._id);
});
return ingredientIDs;
};
const recipe = new Recipe({
name: body.name,
ingredients: (await saveIngredients()) || [],
});
const savedRecipe = await recipe.save();
res.status(201).json(savedRecipe);
});
Returned recipe:
savedRecipe: {
name: 'asd',
ingredients: [],
_id: new ObjectId("62782b45a431e6efb7b8b1a7"),
}
As I said, both ingredients individually and the recipe is saved to the MongoDB after this but not the ingredient IDs in the recipe. The returned recipe has an empty array in ingredients. I guess the recipe is saved too soon before MongoDB can return ObjectIds for the ingredients.
Thanks for any help.
First of all, your post method is an async, so everything inside it is wrapped in a resolved promise automatically.
Do you really need to make your saveIngredients as an async? IMHO, it's better to let the saveIngredients not be in another async.
And then we can remove the empty list, and just wait for the saveIngredients() finish first.
const recipe = new Recipe({
name: body.name,
ingredients: await saveIngredients(),
});
Your guess is correct, the Recipe was saved first because all the conditions are fulfilled because it doesn't need to wait for the saveIngredients since you provided a [] as the default value. And your saveIngredients is run in parallel.
I got it smh. Turns out async in a .map or .foreach doesn't go well. I turned it into a simple for loop. It's still bloated/lot of steps imo but it works!
recipesRouter.post("/", async (req, res) => {
const { body } = req;
const saveIngredients = async () => {
let ingredientIDs = [];
for (let i = 0; i < body.ingredients.length; i++) {
const el = body.ingredients[i];
const ing = new Ingredient({
value: el.value,
label: el.label,
});
const savedIngredient = await ing.save();
ingredientIDs.push(savedIngredient._id);
}
return ingredientIDs;
};
const ingredientIDs = await saveIngredients();
const recipe = new Recipe({
name: body.name,
ingredients: ingredientIDs,
});
const savedRecipe = await recipe.save();
res.status(201).json(savedRecipe);
});

How to create and update referenced documents with mongoose?

I have this setup
var NotesSchema = new mongoose.Schema({
title: String,
category: [{ type: mongoose.ObjectId, ref: "Categories", default: [] }],
},{ timestamps: { createdAt: 'created_at' } });
var CategoriesSchema = new Schema({
name: {type: String, required: true}
})
var Notes = mongoose.model('Notes', NotesSchema);
var Cat = mongoose.model('Categories', CategoriesSchema);
If I want to create a new note and categories I do this
.get('/new', async (req, res) => {
var post1= {
title : "Post: books, thriller, crime and classics",
favorite : true,
categories:[ 'thriller', 'books']
}
try{
var note = post1.categories.map( (cat)=>{
var ca = new Cat({name: cat})
ca.save()
return ca._id
})
post1.category = note
const newNote = new Notes(post1);
const n = await newNote.save()
res.send(n)
} catch(error) {
console.error(error);
};
})
If I were to create a new note that has some new categories I'm stuck.
var post1= {
...
categories:[ 'thriller', 'books', 'classics']
}
'thriller' and 'books' already exist, but 'classics' doesn't.
I tried Cat.find({"name": {$in: post1.categories}}).exec() but I can't seem to look through that data.
All the example tutorials seem to just add one new entry at a time.
Inside your post1.categories.map callback you are creating the Cat documents and call save() on them but you do not await the returned promise. So Note is created before those promises are fulfilled and thus post1.category will be an empty array.
You can fix this by awaiting the save-promises of the categories:
const savePromises = post1.categories.map((cat) => {
const ca = new Cat({name: cat})
return ca.save();
})
const categoryIds = (await Promise.all(savePromises)).map(category => category._id);
post1.category = categoryIds;
// rest of your code

Mongoose is not creating collection name from variable

schema.js
****************************************************************
var nameOfCategory = "hello";
ecomm.createProductCollection = async (categoryName) =>{
nameOfCategory = categoryName;
}
const productSchema = new mongoose.Schema({
productName:{
type: String,
require: true
}
},
// { collection: nameOfCategory }
)
ecomm.productModel = new mongoose.model(nameOfCategory, productSchema, nameOfCategory)
*******************************************************************************************
controller.js
await ecomm.createProductCollection("someDynamicName")
await ecomm.productModel.create(product);
-----------------------------------------------------------------------
Expected Result: Collection created with name "someDynamicName".
Actual Result: Collection created with name "hello".
But while printing in console, nameOfCategory displays "someDynamicName"
This works out when the productSchema is created inside function.
But still could not find the reason why the code in question is not working.
schema.js
****************************************************************
ecomm.createProductCollection = async (categoryName) =>{
nameOfCategory = categoryName;
const productSchema = new mongoose.Schema({
productName:{
type: String,
require: true
}
},
// { collection: nameOfCategory }
)
ecomm.productModel = new mongoose.model(nameOfCategory, productSchema, nameOfCategory)
}

NodeJS Mongoose update document

I'm trying to update or create a document in a MongoDB collection, using "mongoose" this way :
this.statsModel.findOne(
{product_id: requestData.ean},
).then((stats: mongoose.Schema) => {
const productId: string = requestData.ean;
// Update stats with the new scan...
const beforeStats: mongoose.Schema = stats;
const scan: any = {
coords: {
lat: requestData.lat,
lon: requestData.lon,
},
at: new Date(),
};
if (stats) {
stats.scans.push(scan);
stats.update();
} else {
const newStat = new this.statsModel();
newStat._id = requestData.ean;
newStat.product_id = requestData.ean;
newStat.scans = [scan];
newStat.purchases = [];
newStat.save();
}
When this code runs, no new element appears in the "scans" property if had a stats document.
The document is properly created if the stats document was not found.
I tried to change "update()" method to "save()" method, but, this way, i got a "Version error No matching document for the id..."
What i'm doing wrong ?
Regards...
Finally, update the type of the stats promised to Model instead of mongoose.Schema :
this.statsModel.findOne(
{product_id: requestData.ean},
).then((stats: Model<Stats>) => {
const productId: string = requestData.ean;
// Update stats with the new scan...
const beforeStats: mongoose.Schema = stats;
const scan: any = {
coords: {
lat: requestData.lat,
lon: requestData.lon,
},
at: new Date(),
};
if (stats) {
stats.scans.push(scan);
stats.save();
} else {
const newStat = new this.statsModel();
newStat._id = requestData.ean;
newStat.product_id = requestData.ean;
newStat.scans = [scan];
newStat.purchases = [];
newStat.save();
}
So the save() method properly works...
Thx

Mongoose Populate cant get this to work?

book.schema.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const BookSchema = new Schema({
name: {
type: String,
required: true
}
})
module.exports = BookSchema
book.model.js
const mongoose = require('mongoose')
const BookSchema = require('../schema/book.schema')
const Book = mongoose.model('Book', BookSchema)
module.exports = Book
novel.schema.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const NovelSchema = new Schema({
name: {
type: String,
required: true
},
type: {
type: Schema.Types.ObjectId,
ref: 'Book'
}
})
module.exports = NovelSchema
novel.model.js
const mongoose = require('mongoose')
const NovelSchema = require('../schema/novel.schema')
const Novel = mongoose.model('Novel', NovelSchema)
module.exports = Novel
query
// Mongoose Populate cant get this to work
// I am at a loss
Novel.findById('5b87310d41073743856a7c4a').populate({
path: 'books'
})
mongoose populate not working。
Please let me know what I am doing wrong or give me a simple explanation...Thank you...
You are right to use the populate for loading the subdocument, but you need to pass the name of the book field in the novel schema, in your case the name is type.
Here is the link to documentation with some examples: Mongoose Populate
And below is the more one solution to your problem:
let book = await new BookModel({name:"book test"}).save();
console.log('-----------BOOK ITEM-------------');
console.log(book);
let novel = await new NovelModel({name:"novel test",type:book._id}).save();
console.log('-----------NOVEL ITEM-------------');
console.log(novel);
let itemPopulated = await NovelModel.findById(novel._id)
.populate('type')
.then((result) => {
return result;
}).catch((err) => {
console.log(err);
});
console.log('-----------ITEM POPULATED-------------');
console.log(itemPopulated);
And the execution output:
The parameter on the function populate() is the path of the field you want to populate, and also when you use populate or any chained function in mongoose you have to use the exec() function in the ending, so the correct way to do it would be:
Novel.findById('5b87310d41073743856a7c4a').populate({
path: 'type'
}).exec()

Resources