Mongoose Which one is faster .populate() or .find() - javascript

I want to get posts related to a user. which one is faster
to find the User and populate posts
User.findOne({ _id: id}).populate("posts")
Or to search in the Posts model Directly
Post.find({ owner: user_id })

This benchmark code suggests that Post.find({ owner: user_id }) is somewhat faster.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const NUM_USERS = 100;
const NUM_POSTS_PER_USER = 10;
mongoose.connect('mongodb://localhost:27017/testdb', { useNewUrlParser: true });
const userSchema = Schema({
posts: [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});
const postSchema = Schema({
owner: { type: Schema.Types.ObjectId, ref: 'User' },
title: String,
content: String,
});
const User = mongoose.model('User', userSchema);
const Post = mongoose.model('Post', postSchema);
const userIds = [];
async function seed() {
await User.deleteMany({});
await Post.deleteMany({});
for (let i = 0; i < NUM_USERS; ++i) {
const user = new User();
await user.save();
for (let i = 0; i < NUM_POSTS_PER_USER; ++i) {
const post = new Post({
owner: user,
title: Array(50).fill('a').join(''),
content: Array(1000).fill('b').join(''),
});
await post.save();
user.posts.push(post);
}
await user.save();
userIds.push(user._id);
}
}
async function benchmarkPopulate() {
console.time('populate');
for (const id of userIds) {
await User.findOne({ _id: id }).populate("posts");
}
console.timeEnd('populate');
}
async function benchmarkFind() {
console.time('find');
for (const user_id of userIds) {
await Post.find({ owner: user_id });
}
console.timeEnd('find');
}
async function main() {
await seed();
await benchmarkPopulate();
await benchmarkFind();
await benchmarkPopulate();
await benchmarkFind();
await mongoose.disconnect();
}
main();
Output:
populate: 217.534ms
find: 121.905ms
populate: 169.181ms
find: 120.171ms
This is not surprising since Post.find({ owner: user_id }) only needs to query one collection.
These results are fairly consistent across runs (and even if you reverse the order of the benchmarks).
Your mileage may vary and this difference doesn't really matter, especially if you're querying the database over a network.

Related

Fetch API Data In Node JS and Save In MongoDB Database

I'm new to mongooseDB and i'm trying to insert data from this API to the database, it creates the Collection but not the documents, any idea what could i be doing wrong?
import fetch from 'node-fetch';
import mongoose, { mongo } from 'mongoose';
mongoose.connect("mongodb://localhost/highscore");
const postSchema = new mongoose.Schema({
position: {
type: Number,
required: true
},
id: {
type: Number,
required: true
},
score: {
type: Number,
required: true
},
});
const Post = mongoose.model('Players', postSchema);
async function getPlayers() {
const getPlayers = await fetch("http://localhost:3008/api/highscore/players");
const response = await getPlayers.json();
for (let i = 0; i < response.lenght; i++) {
const post = new Post({
position: response[i]['position'],
id: response[i]['id'],
score: response[i]['score'],
});
post.save()
}
}
getPlayers();```
MongoDB provides Api to insert many documents at the same time, example below.
// check if your mongoDb is connected
mongoose.connect(URI).then(err => {
if(err) console.error({err});
else console.info("Database Connected");
});
async function getPlayers() {
const getPlayers = await fetch("http://localhost:3008/api/highscore/players");
try{
const response = await getPlayers.json();
// And then check if you are getting players
console.log({response});
const posts = response.map((player) => ({
position: player['position'],
id: player['id'],
score: player['score'],
}))
// it's not required to await it, just to be sure it did insert
await Post.insertMany(posts);
}catch(error){
console.log({error})
}
}
This line:
for (let i = 0; i < response.lenght; i++) {
response.length
now your array is empty so the save never happens
EDIT
Are you sure about the imports?
Following code works:
//const fetch = require('fetch');
const mongoose = require('mongoose');
mongoose.connect("mongodb://localhost/highscore");
const postSchema = new mongoose.Schema({
position: {
type: Number,
required: true
},
id: {
type: Number,
required: true
},
score: {
type: Number,
required: true
},
});
const Post = mongoose.model('Players', postSchema);
async function getPlayers() {
/*
const getPlayers = await fetch("http://localhost:3008/api/highscore/players");
const response = await getPlayers.json();
for (let i = 0; i < response.lenght; i++) {
*/
const post = new Post({
position: '12',
id: '15',
score: '300',
});
post.save()
} //} getPlayers();
Solution:
import fetch from 'node-fetch';
import mongoose, { mongo } from 'mongoose';
mongoose.connect("mongodb://127.0.0.1:27017/highscore");
const postSchema = new mongoose.Schema({
position: {
type: Number,
required: true
},
id: {
type: Number,
required: true
},
score: {
type: Number,
required: true
},
});
const Post = mongoose.model('Players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/highscore/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
const post = new Post({
position: response.players[i]['position'],
id: response.players[i]['id'],
score: response.players[i]['score'],
});
post.save();
}
}
getPosts();
By default mongodb runs on localhost: 27017
Check your mongodb connection url
mongoose.connect('mongodb://localhost:27017/highscore')

Why could the findOrCreate plugin create several documents at once?

I'm currently working on a MERN application with following/follower function for the users. I decided to create separate schemas for following and follower relationships detached from user schema.
Follower schema
const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;
const followerSchema = mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
follower: {
type: [ObjectId],
ref: 'User'
}
});
followerSchema.plugin(findOrCreate);
const Follower = mongoose.model('Follower', followerSchema);
module.exports = { followerSchema, Follower };
Following schema
const mongoose = require('mongoose');
const findOrCreate = require('mongoose-findorcreate');
const ObjectId = mongoose.Schema.Types.ObjectId;
const followingSchema = mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
following: {
type: [ObjectId],
ref: 'User'
}
});
followingSchema.plugin(findOrCreate);
const Following = mongoose.model('Following', followingSchema);
module.exports = { followingSchema, Following };
The problem however starts in my service where followings are created as supposed to. However, for followers mongoose create 6-8 documents at once with userIds that don't even exist in my db.
Here's the code of the followerService (it's the first function)
const { Follower } = require('../models/followerModel');
const { Following } = require('../models/followingModel');
const { User } = require('../models/userModel');
const mongoose = require('mongoose');
exports.changeFollowStatus = async (user, userId) => {
console.log({ userId: userId, user: user._id });
const newFollowing = await Following.findOrCreate({ userId: user._id }, (err, following, created) => {
console.log({following: following});
if (!err && !isFollowing(following, userId)) {
following.following.push(mongoose.Types.ObjectId(userId));
following.save();
User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), {$inc: {follower: 1}});
} else {
const followingIndex = following.following.indexOf(mongoose.Types.ObjectId(userId));
following.following.splice(followingIndex, 1);
following.save();
User.findByIdAndUpdate(mongoose.Types.ObjectId(userId), { $inc: { follower: -1 } });
}
});
const newFollower = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) }, (err, follower, created) => {
console.log({follower: follower});
if (!err && !isFollower(follower, user._id)) {
follower.follower.push(user._id);
follower.save();
User.findByIdAndUpdate(user._id, { $inc: { following: 1 } });
} else {
const followerIndex = follower.follower.indexOf(user._id);
follower.follower.splice(followerIndex, 1);
follower.save();
User.findByIdAndUpdate(user._id, { $inc: { following: -1 } });
}
});
};
exports.showFollowings = async (userId) => {
const followings = await Following.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });
return followings.following;
};
exports.showFollowers = async (userId) => {
const followers = await Follower.findOrCreate({ userId: mongoose.Types.ObjectId(userId) });
return followers.follower;
};
const isFollowing = (newFollowing, userId) => {
return newFollowing.following.includes(mongoose.Types.ObjectId(userId));
};
const isFollower = (newFollower, userId) => {
return newFollower.follower.includes(userId);
}
Now, my following adding code and follower adding code look almost identical, but for some reason for followers, mongoose creates many more documents. The strange thing is that there is a follower document with the correct userId, but many other with random userIds get created which doesn't happen with followings which works as supposed to.
I also checked whether I pass the correct values and everything seems to be fine. But just for reference, here's the controller function from which I pass the values.
exports.changeFollowingStatus = async (req, res, next) => {
passport.authenticate('jwt', async (err, user, info) => {
if (err) {
console.error({ authError: err });
};
if (info !== undefined) {
console.error({ authError: info.message });
res.status(403).send(info.message);
} else {
console.log({params: req.params});
const userToFollow = req.params.id;
await FollowerService.changeFollowStatus(user, userToFollow);
res.status(200).send({ message: 'success' })
}
})(req, res, next);
};
Could anyone help me with this bug or at least navigate me towards the right direction? I can't seem to find solution to my problem. Thank you all in advance!

Mongoose FindOneAndUpdate not Updating when Pushing an Object to a Nested Array

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.

How to add mongoose transaction and create a document?

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

I am New to nodejs and trying to update a category in categories table but it is not working

> I am trying to update a data using updateOne method but i am not able to debug it why it is not working ?
router.post('/edit-category/:slug', async (req,res) =>{
// res.send(req.body.id);
try{
const updatedPost = await Category.updateOne(
{ _id: req.body.id},
{
$set: { title: req.body.title },
$set: { slug: req.body.slug }
}
);
// updatedPost.update((error) => {if(error){console.log("hiiiiiiiii"+error)}});
res.send(updatedPost);
// console.log(updatedPost);
}catch(error){
console.log({message:error})
}
});
Two possibilities:
Check in DB whether the document is there in DB with req.body.id as _id
Try for the below code:
const ObjectId = require('mongodb').ObjectID;
const updatedPost = await Category.updateOne({ _id: ObjectId (req.body.id)}

Categories

Resources