Implementing text search with Mongoose - node.js

I want to implement text search on my app, and find documents where the field login matches the searched term,
I did the code below and I have no errors but the result in the route is always an empty array, there must be an error somewhere
Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
created_at: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
display_name: {
type: String,
required: true,
index: true,
},
login: {
type: String,
required: true,
index: true,
},
});
UserSchema.index({ login: "text", display_name: "text" });
User = mongoose.model("users", UserSchema);
User.createIndexes();
module.exports = User;
Route
router.post("/users", async function (req, res) {
const { search } = req.body;
const users = await User.find({ $text: { $search: search } });
res.send(users);
});

Related

How to make options (public or private) on Post? in reactjs, nodejs

I'm creating Social Network app using MERN. I have made it so far that users can create posts and have followers and followings. My task is to make an option on the post so it can be public or private. I don't know how to do that. Has anybody idea or example of code how to do it? Thanks!
This is my post model:
const mongoose = require("mongoose");
const postSchema = new mongoose.Schema({
caption: String,
image: {
public_id: String,
url: String,
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
createdAt: {
type: Date,
default: Date.now,
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
comments: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
comment: {
type: String,
required: true,
},
},
],
visibility: {
type: String,
enum : ["public", "private"],
default: "public"
},
});
module.exports = mongoose.model("Post", postSchema);
This is my user model:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Please enter a name"],
},
avatar: {
public_id: String,
url: String,
},
email: {
type: String,
required: [true, "Please enter an email"],
unique: [true, "Email already exists"],
},
password: {
type: String,
required: [true, "Please enter a password"],
minlength: [6, "Password must be at least 6 characters"],
select: false,
},
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post",
},
],
followers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
following: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
resetPasswordToken: String,
resetPasswordExpire: Date,
});
userSchema.pre("save", async function (next) {
if (this.isModified("password")) {
this.password = await bcrypt.hash(this.password, 10);
}
next();
});
userSchema.methods.matchPassword = async function (password) {
return await bcrypt.compare(password, this.password);
};
userSchema.methods.generateToken = function () {
return jwt.sign({ _id: this._id }, process.env.JWT_SECRET);
};
userSchema.methods.getResetPasswordToken = function () {
const resetToken = crypto.randomBytes(20).toString("hex");
this.resetPasswordToken = crypto
.createHash("sha256")
.update(resetToken)
.digest("hex");
this.resetPasswordExpire = Date.now() + 10 * 60 * 1000;
return resetToken;
};
module.exports = mongoose.model("User", userSchema);
and here is the logic how of creating post:
exports.createPost = async (req, res) => {
try {
const myCloud = await cloudinary.v2.uploader.upload(req.body.image, {
folder: "posts",
});
const newPostData = {
caption: req.body.caption,
image: {
public_id: myCloud.public_id,
url: myCloud.secure_url,
},
owner: req.user._id,
};
const post = await Post.create(newPostData);
const user = await User.findById(req.user._id);
user.posts.unshift(post._id);
await user.save();
res.status(201).json({
success: true,
message: "Post created",
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
In your post's model, you can add a "visibility" field with private & public as possible values (one of them default, obviously). Then every time you are querying for that post or list of posts, use that visibility column to decide if the user should be served that post or a 403 response page.
Check this for enum validation.

I want to make a function that create a new task for a specific user

I have 2 models in relation a User model and a Task model each user have inside an empty task array and I want a function that get the user by email and push a new task to the users task array I tried a lot but I don't made that function to work so I need some help here is my code.
User model:
const { Schema } = mongoose;
//connecting mongoose to mongoDB
mongoose.connect("mongodb+srv://tudor:tudor#cluster0.gbojb.mongodb.net/<dbname>?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
const { Post } = require("./PostModel")
const userSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
minlength: [5, 'The password should have more then 5 characters']
},
age: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
maxlength: [300, 'Description should have less then 300 characters']
},
tasks: [{
type: Schema.Types.ObjectId,
ref: "task"
}]
})
const User = mongoose.model('User', userSchema);
exports.User = User
task model
const mongoose = require("mongoose")
const Schema = mongoose.Schema
let TaskSchema = new Schema({
content: String,
owner: {
type: Schema.Types.ObjectId,
ref: "User"
}
})
module.exports = mongoose.model("Task", TaskSchema)
And here I want to make the function :
const createNewTask = async (req, res, next) => {
const userEmail = req.params.id;
}
This is how your function will work:
const createNewTask = async (req, res, next) => {
const userEmail = req.params.id;
// find user first by email
const userData = await User.findOne({email: userEmail});
// add check here if user exist or not (not writing it for now)
// now create task by extract task payload (assuming you have detail in body)
const taskData = await Task.create({
content: req.body.content,
owner: userData._id,
});
// now push task id in user
await User.updateOne({
email: userEmail
}, {
$push: {tasks: taskData._id},
});
}
There can be some errors since didn't tested it but you get the idea how to do it.

mongoose.populate() returning an empty array

I know, this is one of the popular questions out there. On populate I expect it to return the user with his posts, but it's returning an empty array of posts.
Here is my User model.
User.js
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}]
}, { timestamps: true })
const User = mongoose.model("User", userSchema)
module.exports = User
Post.js
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const postSchema = new Schema({
postTitle: { type: String, required: true },
postDescription: { type: String, required: true },
user: { type: Schema.Types.ObjectId, ref: "User" },
}, { timestamps: true }
)
const Post = mongoose.model("Post", postSchema)
module.exports = Post
router.get("/posts/:id", usersController.getUserPosts)
usersController.js
getUserPosts: (req, res) => {
User.findById(req.params.id).populate("posts").exec((err, posts) => {
if (err) console.log(err)
console.log(posts)
})
}
I'm getting this:
{ posts: [],
_id: 5e4e3e7eecd9a53c185117d4,
username: 'rick',
email: 'rick#gmail.com',
createdAt: 2020-02-20T08:08:30.878Z,
updatedAt: 2020-02-20T08:08:30.878Z,
__v: 0 }
Where am I going wrong?

Mongoose find documents where field = req.body.user

I have a user schema and a post schema, wherein a user has many posts. I would like to return all posts that the user has on a route called '/post/dashboard'.
Here is my schemas:
let UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
default: null,
},
profile_pic: {
type: String,
default: '/img/profilepic.png',
},
posts: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}
})
let PostSchema = new Schema({
title: {
type: String,
},
description: {
type: String,
}
original_poster: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
tags: {
type: [String]
}
})
So, for example something like:
app.get('/', (req,res) => {
Post.find({ original_poster: req.session.user }).then((posts) =>{
res.send(JSON.stringify(posts));
}) //where req.session.user is an id (the logged in user's object id or _id)
})
Essentially in sql syntax it might be something like:
SELECT * FROM POSTS WHERE ORIGINAL_POSTER = <req.session.user>
What is the proper way to return all posts by the req.session.user?
It seems that original_poster field represent a reference to User's model, If req.session.user is stored as a string you have to cast it to objectID:
const mongoose = require('mongoose');
...
let userId = mongoose.Types.ObjectId(req.session.user);
Post.find({ original_poster: userId }).then((posts) => {
res.send(JSON.stringify(posts));
});

Getting all Posts that belong to one User and display to pass to the view Node / Express / Mongoose

Below is the code for User model, Post model and the route. I need to query the DB and then pass to the view through the router. What am I missing?
User model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
module.exports = mongoose.model('User', userSchema);
Posts model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var postSchema = new Schema({
postTitle: {
type: String,
required: true
},
postStory: {
type: String
},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
module.exports = mongoose.model('Post', postSchema);
And here is the query in the router that I'm trying but apparently it's not the way to go...
My GET route:
router.get('/dashboard', isLoggedIn, function(req, res) {
Post.find({author:req.user._id}, (err, posts) => {
if(err) {
console.log(err);
} else {
res.render('users/dashboard', {currentUser: req.user, posts: posts});
}
});
});
What am I missing here?
You may want to change the find query to match the proper attribute in the following line:
Post.find({author: req.user._id}, (err, posts) => {
to be:
Post.find({'author.id': req.user._id}, (err, posts) => {
Read more: http://mongoosejs.com/docs/2.7.x/docs/finding-documents.html

Resources