How do I prevent Schema fields from being inserted into subdocument? - node.js

I'm making a dating app in node js and vue, and everything works however I wish to exclude password from being inserted into subdocument upon creation of a conversation. Right now I know that i can say .select('-password') when using User.findOne() but it doesn't work, when adding the user schema as a subdoc to my Conversations schema, which has user_one and user_two, each referring to a User schema. I need the password field, so I can't ommit it when creating a schema. Right Now my code looks like this:
User.findOne({ _id: fromUserId }, (errUserOne, userOne) => {
User.findOne({ _id: toUserId }, (errUserTwo, userTwo) => {
conversation = new Conversation({
_id: mongoose.Types.ObjectId(),
user_one: userOne,
user_two: userTwo
});
conversation.save();
const message = new Message({
_id: mongoose.Types.ObjectId(),
conversation_id: conversation._id,
message: req.body.message,
user_id: fromUserId
});
message.save();
res.sendStatus(201);
});
});
However this code saves the password to the Conversation collection, which I don't want.

User.find({ _id: :{ $in : [fromUserId,toUserId] }, { password:0 } , (err, userArray) => {
//your code goes here
});
Two things, You are querying two time for getting users. You can merge it into single query and for excluding the password field you can pass {password:0}. Which will exclude it in the documents.
also while you define Conversation schema don't make user_one and user_two type of user. Instead define only whatever properties of user you want to save like:
var Conversation = new Schema({
_id : ObjectId,
user_one : {
_id: ObjectId,
//all other fields
},
user_two : {
_id: ObjectId,
//all other fields
},
});

Related

Updating a Subdocument array INSIDE another Subdocument array Mongoose

I am at my wits end with something that is seemingly straightforward:
I need to be able to push new gifts into the Events Array under the specific user. Because each event will have numerous gifts added, I want to keep them all under the user, as they are the one creating the event, and the gifts will live inside of their event where they belong.
The PROBLEM is: when I use the mongoose method 'findByIdAndUpdate', I can only find the main user, and from there, push an event to the events array. What I NEED to be able to do: push gifts to a specific event under that user. I am using mongoose Subdocuments. See my schema below and how I have a subdocument schema (EventSchema) inside of the main user schema, and a subdocument (gift) schema inside the event schema.
SCHEMA:
const Schema = mongoose.Schema;
let giftArr = new Schema({
giftname: String,
giftlink: String,
claimed: Boolean,
claimee: String
})
let eventSchema = new Schema({
eventname: String,
eventowner: String,
date: {
type: Date,
default: Date.now
},
attendees: [
{
attendeename: String
}
],
gift: [giftArr]
})
let userSchema = new Schema({
username: String,
email: { type: String, required: false },
events: [eventSchema]
});
Here are my controllers for my POST & GET routes:
export const insertEventsById = ((req, res) => {
const update = { $push: { events: req.body } }
const id = req.params.userID
Gift.findByIdAndUpdate(id, update, (err, data) => {
if (err) {
console.log(err);
} else {
res.json(data)
console.log(data);
}
})
})
export const getUserById = (req, res) => {
Gift.findById(req.params.userID, (err, user) => {
if(err){
res.send(err)
}
res.json(user)
})
}
To further illustrate, here is my postman GET request for a USER. I can push to the 'events' array (red arrow) as my findByIdAndUpdate method shows above, but when I attempt to go one nested level deeper, into the gift array (green arrow), I cannot find any documentation on that.
I been up and down the mongoose subdocuments and queries pages, and I cannot find a method that will pull specifically the '_id' of the particular event I need. I have even tried the methods on the embedded schemas to specifically look for _id's that way.
Can someone point out where I am going wrong here? Thanks in advance...as always fellow Stacks.

How i can to create new model inside another model?

I have TweetModel and i need to create RatingModel inside, and RatingModel must have a same TweetModel id, because i want to link them for further deletion.
Maybe there are other ways to make rating for posts in mongoose.
I will be very grateful for your help
const tweet = await TweetModel.create({
text: req.body.text,
images: req.body.images,
user: user._id,
rating: ..., // => {retweets[], likes[]}
})
tweet.save()
TweetSchema
RatingSchema
Assuming you already know how to create Schema, you can create 2 different schemas for your tweet and rating. This will create 2 separate collections will inturn be more manageable.
const { text, images } = req.body
const objectId = new mongoose.Types.ObjectId() //create a objectId first.
await TweetModel.updateOne({ _id }, { text, images, user: user._id }, { upsert: true })
await RatingModel.updateOne(....)
We are using updateOne here with the option of {upsert: true} where we will create a new record if record _id don't exist.
You will be able to get the ratings easily with mongoose.populate()
More on { upsert: true } - https://docs.mongodb.com/manual/reference/method/db.collection.update/
Bonus
If you want to create the record in half the time.
const [ tweet, rating ] = await Promise.all([
TweetModel.updateOne({ _id }, { text, images, user: user._id }, { upsert: true })
RatingModel.updateOne(....)
])
Using Promise.all you can execute both update request at the same time.
Bonus 2
If you want to populate ratings inside tweet, add this in your Schema..
TweetModel.virtual('rating', {
ref: 'Rating',
localField: '_id',
foreignField: '_id',
});
Scroll to Populate - https://mongoosejs.com/docs/tutorials/virtuals.html

Save entity with id created in code, mongoose

How can I do to pass the id of a document from outside and not that mongoose generates it?
I need the objects to be stored with the id I tell them, but mongoose overwrites it and saves it with the one he wants. I tried several ways now and nothing happens.
It is an entity that I am distributing through events in several databases, so I need it to be stored with the id I want to maintain the integrity of the data.
Now I have this and it says "document must have an _id before saving", but the id I have already put it, does not recognize it.
The scheme is like this:
const schema = new Schema({
_id: { type: String },
name : { type: String },
});
I also tried with this, and the error is the same:
const schema = new Schema({
_id: { type : String },
name : { type: String },
},
{
_id: false
});
I am passing the object like this:
Item.create({ _id: 'my uuid here', name: 'something' });
but when it is saved it remains with the id generated by mongoose replacing mine, that is, it changes it to me with a _id: '5twt563e3j5i34knrwnt43w'
Your syntax should work, but sometimes mongoose acts weird.
You can try this syntax (works on my project) :
const item = new Item({ name: 'something' });
item._id = 'my uuid here';
await item.save();
Instead of using a random uuid, you need to use a mongoDB objectID. Mongoose can also create that,
var mongoose = require('mongoose');
var id = mongoose.Types.ObjectId();
Store this id in the collection,
Item.create({ _id: id, name: 'something' });

How to use ref to store a document correctly in mongodb - mongoose?

I am trying to store a ref of a user model in my users - followers Array:
The model looks something like this:
User = require('../models/user.js');
ObjectId = mongoose.Schema.Types.ObjectId;
User = new Schema({
followers: [{ type: ObjectId, ref: 'User' }],
Now I am trying to store every time a user follows a user like so:
User.findByIdAndUpdate({_id: myId}, { $addToSet: {followers: user._id,
However, this only stores the string and not the whole user object? Is that how it is suppose to be? If so, then to grab it out the rest of the info do I just need to do a populate query?
If it is suppose to store the whole object then does it update as well as the object gets updated?
I was going to remove the question as I figured it out, but I see that people up-voted it so to help them out, I shall post my discoveries.
Apparently it will just store the id, and to then call it I used a basic populate call on it like so:
User
.findOne({ _id: myId })
.populate('followers', '_id name count') //
.exec(function (err, doc) {
if (err) return handleError(err);
})

Mongoose populate return undefined

I'm currently trying to develop an app using mongo and node.js.
I am facing a problem when I want to build a query who use the populate option.
Here are my Schemas :
// Schema used by mongoose
var userSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
login: String,
password: String,
movies: [ { type: mongoose.Schema.Types.ObjectId, ref: movieModel} ],
admin: Boolean
},{ collection: "user" });
var movieSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
title: String,
}, { collection: "movie" });
As you can see, each user have an array of movies, this array contains valid ids of movies. What I want is to have the movies of an user. This is how I build my query :
var query = userModel.findOne({ login: req.session.user["login"] })
.populate("movies");
query.exec(function(err, user)
{
if (err)
throw err;
console.log(user.movies[0].title);
});
The query is executed successfully, but when I try to display the title of the first movie at the console.log line I got an error "TypeError: Cannot read property 'title' of undefined". I checked the documentation of mongoose and don't understand why I'm getting this error.
I would like to specify that my database contains valid data.
I put mongoose in debug mode, and this is the query that is executed :
Mongoose: user.findOne({ login: 'user' }) { fields: undefined }
Mongoose: user.find({ _id: { '$in': [ ObjectId("52e2a28949ad409834473e71"), ObjectId("52e2a28949ad409834473e79") ] } }) { fields: undefined }
The two ids on the second line are valid ids of movies. I would like to display their name.
Thanks a lot for your help.
What is the value of this: ref: movieModel?
movieModel would need to be set to the string like "Movie". See here for more information. It will need to match the identifier provided when you create the Movie model.
var Movie = mongoose.model('Movie', movieSchema);
So, you might have in a schema:
var userSchema = mongoose.Schema({
name: String,
favorite_movies: { type: Schema.Types.ObjectId, ref: 'Movie' }
});
var User = mongoose.model('User', userSchema);
I've used the string Movie in both the Schema definition and when creating the Movie type. They need to be exactly the same.
MongooseJs uses the string name of the Model to determine where to fetch the documents from when using ref and populate.
In the debug output, you can see how Mongoose is actually querying the wrong collection, as I'd expect it to be using movies.find to find the relevant Movie documents.

Resources