I'm just starting out whit node and mongoose and I'm trying to create a user, then create a stripe customer with a stripe generated id and save the response in a user Map field stripeDetails.
Here is the schema:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
photoUrl: { type: String, required: true },
phoneNumber: { type: String, required: false },
address: { type: String, required: false },
zipCode: { type: String, required: false },
city: { type: String, required: true },
region: { type: String, required: true },
country: { type: String, required: true },
isVerified: { type: Boolean, required: false, default: false },
lastLogin: { type: Number, required: false, default: Date.now },
stripeDetails: {type: Map, required: false}
},
{ timestamps: true });
module.exports = mongoose.model('User', userSchema, 'Users');
I tried setting the stripeDetails field like
.then(stripeCustomer => {
console.log('Stripe.customer.create', stripeCustomer);
result.set('stripeDetails', stripeCustomer);
result.save();
...
but is not working.. I settle to update the record's field but is a bit messy..
exports.createUser = async (req, res) => {
const user = req.body;
console.log('User is :', user);
/// Creat use in DB
User.create(
user,
function (err, result) {
if (err) {
console.log('Mongoose createUser error: ', err);
res.statut(503).send({ error: "Internal error" });
return;
}
console.log('Mongoose createUser: ', result);
res.status(200).send({
message: "User created successfully!",
data: result
});
/// Create stripe customer
stripe.customers.create({
"address": {
"city": user.city,
"state": user.region,
"country": user.country,
"postal_code": user.zipCode
},
"balance": 0,
"created": Date.now,
"email": user.email,
"name": user.name,
"phone": user.phoneNumber,
"preferred_locales": [],
"shipping": null,
"tax_exempt": "none"
})
.then(stripeCustomer => {
console.log('Stripe.customer.create', stripeCustomer);
// save stripe details to db
//not working..
// result.set('stripeDetails', stripeCustomer);
// result.save();
// working
User.findByIdAndUpdate(
result.id,
{stripeDetails: stripeCustomer},
{ new: true },
function(err, result) {
if (err) {
console.log('Stripe customer not updated to db: ', err);
}
if (result != null){
console.log('Stripe customer updated to DB', result);
} else {
console.log('Stripe customer to update not found in db ');
}
}
);
})
.catch(error => {
console.log('Stripe.customer.create error: ', error);
});
}
);
};
also I can't access the stripeDetails.id value for when I need to delete the user..
exports.deleteUserById = async (req, res) => {
const id = req.params.id;
User.findByIdAndDelete(
id,
function (err, result) {
if (err) {
console.log('Mongoose deleteUserById error: ', err);
res.statur(505).send({ errro: "Internal error" });
}
if (result != null) {
console.log('Mongoose deleteUserById: ', result);
res.status(200).send({
message: "User found!",
data: result
});
console.log('stripe id is: ', result.stripeDetails['id']);
stripe.customers.del(`${result.stripeDetails['id']}`)
.then(stripeCustomer => {
console.log('Stripe.customer.delete', stripeCustomer);
})
.catch(error => {
console.log('Stripe.customer.delete error: ', error);
});
} else {
console.log("Mongoose deleteUserById: user not found");
res.status(404).send({ message: "User not found" });
}
});
}
I could use the mongoose _id as the stripe id but I rather use their own separate id generators and keep the ids separate, and get used to work with maps in mongoose. Can you see what I'm doing wrong with in writing and reading stripeDetails?
Try to change stripeDetails in Schema to be of type Object:
stripeDetails: {type: Object, required: false}
Now you can do this:
.then(stripeCustomer => {
result.stripeDetails.details = stripeCustomer;
User.findByIdAndUpdate(result.id, result).then((result)=>{
console.log('User updated.');
})
})
Note that when you are using Map as a type, you should access the value of a key with .get(). So try to access stripe_id like this:
let stripe_id = result.stripeDetails.get("id");
stripe.customers.del(stripe_id)
.then(stripeCustomer => {
console.log('Stripe.customer.delete', stripeCustomer);
})
.catch(error => {
console.log('Stripe.customer.delete error: ', error);
});
Check it here.
Related
Everything works fine but I have the above-mentioned error while deleting something with id in mongoose. I'm looking for a solution for last 3 days :( but nothing works for me.
// Delete a quote
router.delete("/delete/:id", async (req, res) => {
const result = await Post.findOneAndDelete({ _id: req.params.id }, (err, data) => {
if (err) {
res.status(500).json({
success: false,
message: "Sever error.",
});
} else {
res.status(200).json({
success: true,
message: "Post Deleted",
result,
});
}
});
res.json(result);
});
And my post schema:
const PostSchema = mongoose.Schema({
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Posts", PostSchema);
I have a User schema, with a messages array. The message array is filled by conversations id and referenced to a Conversation schema.
I want to fetch all conversations from a user, sort them by unread and then most recent messages. Finally, I must only return an array of lastMessage object.
For the moment, I have only managed to populate the whole user object.
Here is the Conversation Schema:
const conversationSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
messages: [{ message: { type: String }, authorId: { type: String } }],
lastMessage: {
authorId: { type: String },
snippet: { type: String },
read: { type: Boolean },
},
},
{ timestamps: true }
);
conversationSchema.index({ name: 1 });
module.exports = mongoose.model("Conversation", conversationSchema);
And here is my code:
router.get("/conversations", async (req, res) => {
try {
const { userId } = req.query;
const user = await User.findById({ _id: userId }).populate("messages");
.sort({ updatedAt: 1, "lastMessage.read": 1 });
return res.json({ messages: user.messages });
} catch (err) {
console.log("error", err);
return res.json({ errorType: "unread-messages-list" });
}
});
How to do this?
I'm trying to post a comment on to my posts for my MERN app but I'm running into an issue where the comment (Posts.findOneAndUpdate) seems to posting the comments twice. I read a few posts on SO that described the issue to be the way mongoose handles queries but I must be missing something.
If anyone could explain what I'm doing wrong I would greatly appreciate it!
Route I'm using:
router.post('/newReply/:id', async function(req, res) {
const body = req.body
if (!body) {
return res.status(400).json({
success: false,
error: 'No text entered!',
})
}
const reply = new Replies(body)
if (!reply) {
return res.status(400).json({ success: false, error: err })
}
await Posts.findOneAndUpdate(
{ _id: req.params.id },
{
"$inc": { "replies": 1 },
"$push": { "comments": reply },
},
{
new: true
},
(err) => {
if (err) {
return res.status(404).json({
success: false,
error: err,
message: 'Post not found!',
})
}
return res.status(200).json({
success: true,
id: reply._id,
message: 'Reply created!',
reply: reply.reply,
points: reply.points,
createdAt: reply.createdAt
})
})
.catch(err => console.log(err))
})
Posts Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const PostsSchema = new Schema({
post: {
type: String,
required: true
},
points: {
type: Number,
default: 0
},
voters: {
type: Array
},
upvotedBy: {
type: Array
},
downvotedBy: {
type: Array
},
createdAt: {
type: Date,
default: Date.now
},
replies: {
type: Number,
default: 0
},
comments: {
type: Array
},
user_id: {
type: 'string'
},
deleted: {
type: Boolean,
default: false
}
});
module.exports = Posts = mongoose.model("posts", PostsSchema);
When I execute the function findOneAndRemove() and pass in the required parameters, it shows the error 'TypeError: Cannot read property '_id' of undefined'. My mongodb have the attribute '_id'
I tried findById(). It is working but if I defined findOneAndRemove({_id: req.params.id}), the error occurs.
**router**
router.delete('/delete/:id', async (req, res) => {
try {
var id = req.params.id;
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndDelete({ _id: id, createdBy: req.user._id });
console.log('team', team);
if (!team)
return res.status(404).send();
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
**Team Model**
var mongoose = require('mongoose');
const teamSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
trim: true
},
country: {
type: String,
required: true,
trim: true
},
yearFounded: {
type: Date,
required: true
},
ground: {
type: String,
required: true,
trim: true
},
capacity: {
type: Number,
required: true,
},
manager: {
type: String,
required: false,
},
website: {
type: String,
required: false,
},
imagePath: {
type: String,
required: false,
},
description: {
type: String,
required: false
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
}
}, {
timestamps: true
})
teamSchema.index({ name: "text", manager: "text", ground: "text", country: "text" });
teamSchema.virtual('players', {
ref: 'Player',
localField: '_id',
foreignField: 'team'
})
const Team = mongoose.model('Team', teamSchema);
module.exports = Team
findOneAndRemove returns the removed document so if you remove a document that you later decide should not be removed, you can insert it back into the db. Ensuring your logic is sound before removing the document would be preferred to checks afterward IMO.
findOneAndDelete has the sort parameter which can be used to influence which document is updated. It also has a TimeLimit parameter which can control within which operation has to complete
try this
router.delete('/delete/:id', async (req, res) => {
try {
let id = {_id:req.params.id};
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndRemove({ _id: rid, createdBy: req.user._id });
console.log('team', team);
if (!team)
return res.status(404).send();
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
The answer is I forget to add middleware 'authenticate' and hence the createdBy params req.user._id is forever undefined. The solution.
Routes
router.delete('/delete/:id', authenticate, async (req, res) => {
try {
var id = req.params.id;
if (!ObjectID.isValid(id))
return res.status(404).send();
let team = await Team.findOneAndRemove({ _id: id, createdBy: req.user._id });
if (!team)
return res.status(404).send();
removeImage(team.imagePath);
res.status(201).json({
message: 'Team Deleted',
result: { team }
});
} catch (e) {
console.log(e);
res.status(400).send(e);
}
});
Middleware
let authenticate = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) {
throw new Error()
}
req.token = token;
req.user = user;
next()
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' })
}
};
In my application there are 4 features I need to implement:
A user can follow another user.
A user can unfollow another user.
A user can see a list of all of their followers.
A user can see a list of all whom they are following.
I believe I have implemented 1. and 2. correctly. I created a follow schema as you can see below in my follow.model and I have created follow.controller with two methods, to store (follow) and destroy (unfollow).
Now I want to to implement 3. and 4. I created two arrays in the user.model schema, one for following and one for followers. When I return the user in my user.controller, how do I populate the following and followers array? At the moment they are empty.
follow.model.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var FollowSchema = new Schema({
follower: {
type: Schema.Types.ObjectId,
ref: 'User'
},
followee: {
type: Schema.Types.ObjectId,
ref: 'User'
}
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
module.exports = mongoose.model('Follow', FollowSchema);
follow.controller.js
'use strict';
const User = require('../models/user.model');
const Follow = require('../models/follow.model');
class FollowController {
constructor() {
}
store(req, res) {
let follower = req.body.follower;
let followee = req.params.id;
let follow = new Follow({
follower: follower,
followee: followee,
});
follow.save(function (err) {
if (err) {
return res.status(404).json({
succes: false,
status: 404,
data: {},
message: "There was an error trying follow the user."
});
}
return res.status(200).json({
success: true,
status: 200,
data: follow,
message: 'Successfully followed user'
});
});
}
destroy(req, res) {
let follower = req.params.followerid;
let followee = req.params.id;
Follow.remove({ 'follower': follower, 'followee': followee }, (err, result) => {
if (err) {
return res.status(404).json({
success: false,
status: 404,
data: {},
message: "Error removing record"
});
}
return res.status(201).json({
success: true,
status: 201,
data: {},
message: "Successfully unfollowed user"
})
});
}
}
module.exports = FollowController;
user.model.js
let UserSchema = new Schema({
email: {
address: {
type: String,
lowercase: true,
//unique: true,
},
token: String,
verified: {
type: Boolean,
default: false,
},
},
password: {
type: String,
},
following: [{
type: Schema.Types.ObjectId, ref: 'Follow'
}],
followers: [{
type: Schema.Types.ObjectId, ref: 'Follow'
}],
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
user.controller.js
show(req, res) {
let id = req.params.id;
User.findOne({ '_id': id },
function (err, user) {
if (err) {
return res.json(err);
}
return res.json(user);
});
}
You just need to populate these fields:
User.findOne({ '_id': id }, (err, user) => {
if (err) return res.json(err);
return res.json(user);
}).populate([
{ path: 'following' },
{ path: 'followers' }
]);