I have two models Post and Users and I want to populate the posts fields
const PostSchema = new Schema({
text: {
type: String
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
}
})
const UserSchema = new Schema({
username: {
type: String,
}
})
router.post('/', async (req,res) => {
try {
let joe = new User({username: "joe"})
await joe.save()
let postText = {text: "my name is joe", author: joe._id}
let postByJoe = new Post(postText)
await postByJoe.save()
let users = User.find().populate('author')
res.json({users})
} catch (error) {
console.log(error.message)
res.json(error.message)
}
})
The problem is that I get an error and I don't know what to make of it. I'm not sure at all what the issue is. Any help would be greatly appreciated
"Converting circular structure to JSON\n --> starting at object with constructor 'NativeTopology'\n | property 's' -> object with constructor 'Object'\n | property 'sessionPool' -> object with constructor 'ServerSessionPool'\n --- property 'topology' closes the circle"
What you have in your schema is different, you can only populate the Schema.Types.ObjectId field in your schema. Seems you are trying to populate the author field of the Post model.
Replace this line let users = User.find().populate('author') with this let users = Post.find().populate('user') Your code should be like the one below:
router.post('/', async (req,res) => {
try {
let joe = new User({username: "joe"})
await joe.save()
let postText = {text: "my name is joe", author: joe._id}
let postByJoe = new Post(postText)
await postByJoe.save()
let data = await Post.find().populate('user')
// map through the object returned
const users = data.map((user) => user)
res.json({users})
} catch (error) {
console.log(error.message)
res.json(error.message)
}
})
Read more about mongoose population here
Related
So Im using mongoose and mongo atlas. I have a single document with a structure as follows:
{_id: ObjectId("3u3ui4t432) ,
name: cat1,
items :
[
{cat1_item1: "something"},
{cat1_item2: "something"}
]}
{_id: ObjectId("3u3uir3bi2) ,
name: cat2,
items :
[
{cat2_item1: "something"},
{cat2_item2: "something"}
]}
currently this endpoint retrieves the entire document, i am just trying to access one category at a time based of a param either url or body
//this gets the specific document i want, but i would prefer to get that document through something like this.
// findOne({ category: req.body.category })
app.post('/targetCategory', async (req, res) => {
const categoryName = req.body.category
categoryCollection.findOne({ _id: "62b9353730ac42a7d390f5ad" }, (err,
data) => {
if (err) {
console.log(err)
} else {
res.send(data)
console.log(categoryName)
}
})
})
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const categorySchema = Schema({
categories: {
}
})
module.exports = mongoose.model('categoryCollection', categorySchema)
basically I want to use params(?) to only access one category at a time to minimise data sent to the frontend. How do i go about using something like findOne() with the param being either category1 or category2 as I only want the array inside. I am using mongoose, node and express.
model
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const categorySchema = Schema({
name: String,
// items placeholder, modify if required
items: String[]
})
const Category = mongoose.model('Category', categorySchema)
module.exports = Category
the controller you can use
app.post('/listOne', async (req, res) => {
try {
const categoryData = await Category.findOne({name: req.body.category})
res.send({category: categoryData})
}
catch (e) {
console.log(e)
}
})
another controller solution I suggest
app.get('/category/:name', async (req, res) => {
try {
const categoryData = await Category.findOne({name: req.params.name})
res.send({category: categoryData})
}
catch (e) {
console.log(e)
}
})
To find single data in collection you can use this function or read this in mongoose docs https://mongoosejs.com/docs/api.html#model_Model.findOne
// Find one adventure whose `country` is 'Croatia', otherwise `null`
await Adventure.findOne({ country: 'Croatia' }).exec();
// using callback
Adventure.findOne({ country: 'Croatia' }, function (err, adventure) {});
// select only the adventures name and length
await Adventure.findOne({ country: 'Croatia' }, 'name length').exec();
and to get parameter in express you can use this
app.get('/users/:userId/books/:bookId', (req, res) => {
res.send(req.params)
})
When trying to push to a nested array it's not updating in my database with the following code:
const obj = {
key: key,
user: user,
description: description,
date: Date.now(),
guildId: guildId,
};
const guild = await this.GuildModel.findOneAndUpdate(
{ guildId: guildId },
{ $push: { 'guildData.commandLogs': obj } },
);
My schema:
const GuildSchema = {
guildId: { type: String },
guildData: {
commandLogs: [CommandLogsSchema],
},
Any idea why my database isn't updating?
I think you might have some typos in your model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const GuildSchema = new Schema({ guildId: { type: String },
guildData: {
commandLogs: [CommandLogsSchema], })
in your controller, the filter condition that you're passing is not clear, which guildId you are using? also when you call the guildData.commandLogs field to update it you are missing brackets
const filter = { guildId: heretheactualId };
const update = { { $push: { commandLogs: obj} }};
const guild = await this.GuildModel.findOneAndUpdate(
filter,
update,
);
this is not going to fix your problem because I don't know what kind of errors you're having or your database model but these tips can already help.
I want to add a mongoose transaction in the POST method. When creating the transaction it should be creating a document called stock. Can anybody help me figure out what should I do here? I have a node/express/mongoose app with the following:
GoodsRecivedNote controller
router.post('/', async (req, res) => {
const session = await mongoose.startSession()
try {
const _id = await getNextSequence('goodsReceivedNote')
req.body.id = _id
const goodsReceivedNote = new GoodsReceivedNote(req.body)
const stocks = new Stock(req.body)
await goodsReceivedNote.save()
//use mongoose transaction
//creates a loop(data get from the arry called cart in goodsrecivednote)
for (const item of data) {
//insert stock modal(orderNo, packingId, orderSize, poNumber)
item.create({})
//insert(data, {session})
}
await session.commitTransaction()
res.sendStatus(200)
} catch (error) {
await session.abortTransaction()
return res.sendStatus(500)
} finally {
session.endSession()
}
})
GoodsRecivedNote model
const goodsReceivedNoteSchema = new Schema(
{
id: Number,
poNumber: String,
orderedDate: String,
supplier: String,
orderNo: String,
cart: [
{
packingId: Number,
actualSize: String,
orderSize: String,
brandId: Number,
artWork: String,
receivedQty: Number,
grnDate: String,
},
],
},
)
module.exports = mongoose.model(
'GoodsReceivedNote',
goodsReceivedNoteSchema
)
Stock model
const stockSchema = new Schema(
{
id: Number,
poNumber: Number,
orderNo: String,
packingId: Number,
orderSize: String,
receivedQty: Number,
availableQty: Number,
},
)
module.exports = mongoose.model(
'Stock',
stockSchema
)
Maybe you can try something like this
const session = await mongoose.startSession()
session.startTransaction()
const opts = { session }
const stocks = await new Stock(req.body).save(opts)
await goodsReceivedNote.save(opts)
...the rest of your code
When ever you call Save Update or Delete please add opts as option
Answer by 21bn gets the work done but withTransaction() is way better than startTransaction().
I recommend you use withTransaction instead.
const session = await mongoose.startSession();
await session.withTransaction(async (session) => {
// For create..
collection.create({something:"something"},{session:session});
});
For insertmany, updatemany, the rule is basically the same..
collection.updateMany({find_something:"something"},{name:"Some name"},{session:session});
If you want to find a document using session..
collection.findOne({_id: "some_id"}).session(session));
const postSchema = new mongoose.Schema({
post:[
{postId: String},
{commentComponent: [
{comment: [String]},
]}
]
})
const Posts = mongoose.model('Posts', postSchema)
This is the definition of the schema for modeling the mongodb
const postLinks = await getPostLinks();
const posts = new Posts({
for (let i = 0; i < postLinks.length; i++) {
const comment = await getComment(postLinks[i]) // here it takes postLinks as a paramaeter to get an array of comment
post: [
{postId: postLinks[i]},
{commentComponent: [
{comment: comment}
]}
]
}
})
const result = await posts.save()
is there a way of iterating inside this instance because the for loop here is not working
You need to pass an object to the Posts constructor with a property called post (which probably should be called posts, but will keep the original name below), and for this property, you need to specify an array.
This array can be built by using Array.prototype.map and Promise.all:
const post = await Promise.all(
postLinks.map(async (postLink) => {
const comment = await getComment(postLink);
return {
postId: postLink,
commentComponent: [{ comment }],
};
})
);
const posts = new Posts({ post });
const result = await posts.save();
But if you prefer, you can use the traditional for-loop (more similar to what you were trying to do) as well:
const post = [];
for (let i = 0; i < postLinks.length; i++) {
const comment = await getComment(postLinks[i]);
post.push({
postId: postLinks[i]},
commentComponent: [{ comment }]
});
}
const posts = new Posts({ post });
const result = await posts.save();
Based on your code example I am not certain what you are attempting to do. When using a Model and trying to create you can think of as a new singular record. If you are trying to insert many links into a single record I would suggest comma separating them then inserting that into your MongoDB.
But you cannot iterate inside your Posts class like that.
If I were you I would set up my file something like this:
file: models/Post.js:
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema({
text: {
type: String,
trim: true,
required: [true, 'Please add some text']
},
link: {
type: String,
required: [true, 'Please add link']
},
createdAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Post', PostSchema);
Then create a controller js file
file: controllers/posts.js:
const Post = require('../models/Post');
// #desc Add Post
// #route POST /api/v1/posts
// #access Public
exports.addPost = async (req, res, next) => {
try {
// get post data from the request
// mongo returns a promise so await on it
const post = await Post.create(req.body);
return res.status(201).json({
success: true,
data: post
});
} catch (err) {
if(err.name === 'ValidationError') {
const messages = Object.values(err.errors).map(val => val.message);
return res.status(400).json({
success: false,
error: messages
});
} else {
return res.status(500).json({
success: false,
error: 'Server Error'
});
}
}
}
then in your router file, you can use your controller:
routes/post.js
const express = require('express');
const router = express.Router();
const { addPost } = require('../controllers/posts');
router
.route('/')
.post(addPost);
module.exports = router;
Update: Been some time. But back then decided not to use Mongoose. Main reason being that we couldn't really come up with a great reason for using an ORM when using mongo and javascript.
I've been trying to create a database/model with Mongoose which is basically just a user database where the username is unique. Sounds simple enough, but for some reason I've been unable to do so.
What I've got so far is this:
var mongoose = require('mongoose').Mongoose,
db = mongoose.connect('mongodb://localhost/db');
mongoose.model('User', {
properties: [
'name',
'age'
],
cast: {
name: String,
age: Number
},
//indexes: [[{name:1}, {unique:true}]],
indexes: [
'name'
]
/*,
setters: {},
getters: {},
methods: {}
*/
});
var User = db.model('User');
var u = new User();
u.name = 'Foo';
u.save(function() {
User.find().all(function(arr) {
console.log(arr);
console.log('length='+arr.length);
});
});
/*User.remove({}, function() {});*/
It just doesn't work. The database is created alright, but the username is not unique. Any help or knowledge of what I'm doing wrong?
You need to define the schema. Try this: (
var mongoose = require('mongoose').Mongoose,
db = mongoose.connect('mongodb://localhost/db'),
Schema = mongoose.Schema;
mongoose.model('User', new Schema({
properties: [
'name',
'age'
],
[...]
}));
For Mongoose 2.7 (tested in Node v. 0.8):
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var db = mongoose.connect('mongodb://localhost/db');
var User = new Schema({
first_name: String,
last_name: String
});
var UserModel = mongoose.model('User', User);
var record = new UserModel();
record.first_name = 'hello';
record.last_name = 'world';
record.save(function (err) {
UserModel.find({}, function(err, users) {
for (var i=0, counter=users.length; i < counter; i++) {
var user = users[i];
console.log( "User => _id: " + user._id + ", first_name: " + user.first_name + ", last_name: " + user.last_name );
}
});
});
Try giving right path in var mongoose = require('mongoose').Mongoose,
. It worked for me..
#
my code
require.paths.unshift("/home/LearnBoost-mongoose-45a591d/mongoose");
var mongoose = require('mongoose').Mongoose;
var db = mongoose.connect('mongodb://localhost/db');
mongoose.model('User', {
properties: ['first name', 'last name', 'age', 'marriage_status', 'details', 'remark'],
});
var User = db.model('User');
var record = new User();
record.first name = 'xxx';
record.last name = 'xxx';
record.age = 'xxx';
record.marriage_status = 'xxx';
record.details = 'xxx';
record.remarks = 'xxx';
record.save(function() {
User.find().all(function(arr) {
console.log(arr);
console.log('length='+arr.length);
});
});
//User.remove({}, function() {});
Compile it with node filename.js
good luck..
You should define your unique indexes before running your app for the first time. Otherwise, you need to drop your collection and start over. Also, mongoose will not throw an error when you attempt to save { name: 'user1' } when 'user1' already exists.
Learnboost recently uploaded a set of examples https://github.com/LearnBoost/mongoose/tree/master/examples
I am aware this question is 10 years old and the original poster abandoned Mongoose, but since it pops up near the top of Google searches I felt I would provide a fresh answer.
Providing a complete basic example, using Typescript. I have added comments in the
code, where appropriate.
async function mongooseHelloWorld () {
const url = 'mongodb://localhost/helloworld';
// provide options to avoid a number of deprecation warnings
// details at: https://mongoosejs.com/docs/connections.html
const options = {
'useNewUrlParser': true,
'useCreateIndex': true,
'useFindAndModify': false,
'useUnifiedTopology': true
};
// connect to the database
console.log(`Connecting to the database at ${url}`);
await mongoose.connect(url, options);
// create a schema, specifying the fields and also
// indicating createdAt/updatedAt fields should be managed
const userSchema = new mongoose.Schema({
name:{
type: String,
required:true
},
email: {
type: String,
required: true
}
}, {
timestamps: true
});
// this will use the main connection. If you need to use custom
// connections see: https://mongoosejs.com/docs/models.html
const User = mongoose.model('User', userSchema);
// create two users (will not be unique on multiple runs)
console.log('Creating some users');
await User.create({ name: 'Jane Doe', email: 'jane.done#example.abcdef' });
await User.create({ name: 'Joe Bloggs', email: 'jane.done#example.abcdef' });
// Find all users in the database, without any query conditions
const entries = await User.find();
for (let i = 0; i < entries.length; i++) {
const entry = entries[i] as any;
console.log(`user: { name: ${entry.name}, email: ${entry.email} }`);
}
}
// running the code, and making sure we output any fatal errors
mongooseHelloWorld()
.then(() => process.exit(0))
.catch(error => {
console.log(error)
});
Note, this was validated with Mongoose 5.9.26, running against Mongo 4.0.13.