Mongoose how to update array from child to parent - javascript

I have following schema for Audio.
const AudioSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
uploaderId: {
type: String,
required: true
}
});
Instead of referencing the User, I just store the User's _id as uploaderId.
In my User schema I also have audioFiles: [Audio] array for all audio files that user has uploaded.
const UserSchema = new mongoose.Schema({
...,
audioFiles: [Audio]
});
When I try to update my AudioSchema from my REST Api, I can change all the properties and that works, but after saving this Audio model those changes doesn't affect the User model.
Now I created a new branch and try to change uploaderId to UserSchema. But I wonder is there a solution for this without referencing the UserSchema

I managed to do this with help of MongooseArray.prototype.pull method.
Steps for solving this problem is really easy.
First I get the User that is associated with AudioModel.uploaderId, then I used the user.audioFiles.pull() method. Correct code is below.
let user = await UserService.getUser(userId);
await user.audioFiles.pull({
_id: audioId //audioId is the id which i'm trying to remove from array
});
await user.save();
I also added try-catch block to handle errors.
Anyone having this kind of issue can use the link below to get more information about MongooseArray.prototype.pull method.
Also you can check the other answers in this post.

Related

Mongoose append element to array if doesn't exist remove if it does

I have a user model that can have an array of images;
const UserSchema = new mongoose.Schema({
email: {
type: String
},
password: {
type: String
},
favorites:[imageschema]
});
I have a button on my frontend that I need to toggle the "favorite" status of the image; i.e. have it present in the "favorites" array of my user.
So essentially I want to get the user and then I want it to remove the image from the favorites array if its present in it, add it to the array if its not.
Assuming I use my user's email address to find his/her document like so;
User.Find({email:email}).exec.then(...)
What do I need to add to accomplish this?

Mongoose: Reference schema in properties or add as an array? which is better

For example if i have two schemas User and Post , should i add User reference in Post's properties, or add Post schema as an array inside User Schema? which is better performance wise( and other aspects).
var PostSchema = new mongoose.Schema({
title: String,
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
});
OR
var UserSchema = new mongoose.Schema({
name: String,
posts: [PostSchema]
});
var PostSchema = new mongoose.Schema({
title: String,
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
});
I think this way is better than others.
You should have a reference to the user in the PostSchema.
This is the better approach because a user can have multiple posts and if you save the posts in the UserSchema as an array, that array can grow infinitely. This can cause problems because there's a limit on the max size of a mongodb document. Single mongodb document cannot be greater than 16Mb.
Saving Posts in the User schema is better from the performance perspective but considering the limit on the size of mongodb document and the fact that a user can have many posts, a child document (Post) referencing its parent document (User) is the better approach here.

associating a GridFS-Stream file to a Schema with Mongoose

I am writing an API for my application, using Mongoose, Express, and GridFS-Stream. I have a Schema for the articles the user will create:
var articleSchema = mongoose.Schema({
title:String,
author:String,
type: String,
images: {type: Schema.Types.ObjectId, ref: "fs.files"},
datePublished: { type: Date, default: Date.now },
content: String
})
var Article = mongoose.model("article", articleSchema, "articles");
and my grid-fs set up for when a user uploads an image:
api.post('/file', fileUpload.single("image"), function(req, res) {
var path = req.file.path;
var gridWriteStream = gfs.createWriteStream(path)
.on('close',function(){
//remove file on close of mongo connection
setTimeout(function(){
fs.unlink(req.file.path);
},1000);
})
var readStream = fs.createReadStream(path)
.on('end',function(){
res.status(200).json({"id":readStream.id});
console.log(readStream);
})
.on('error',function(){
res.status(500).send("Something went wrong. :(");
})
.pipe(gridWriteStream)
});
Right now it's set up to when the user chooses an image, it automatically uploads it via gridfs-stream, puts it in a temp folder, then deletes it when it is uploaded to the mongo server, and in the console returns what the ObjectId is. Well thats all find and dandy, but we need to associate this ID with the articleSchema, so when we call that article in the app, it will display the associated image.
on our creation/update of an article when the user hits submit:
createArticle(event) {
event.preventDefault();
var article = {
type: this.refs.type.getValue(),
author: this.refs.author.getValue(),
title: this.refs.title.getValue(),
content: this.refs.pm.getContent('html')
};
var image = {
images: this.refs.imageUpload.state.imageString
};
var id = {_id: this.refs.id.getValue()};
var payload = _.merge(id, article, image);
var newPayload = _.merge(article, image)
if(this.props.params.id){
superagent.put("http://"+this.context.config.API_SERVER+"/api/v1.0/article/").send(payload).end((err, res) => {
err ? console.log(err) : console.log(res);
});
} else {
superagent.post("http://"+this.context.config.API_SERVER+"/api/v1.0/article").send(newPayload).end((err, res) => {
err ? console.log(err) : console.log(res);
this.replaceState(this.getInitialState())
this.refs.articleForm.reset();
});
}
},
So what I need it to do, is call the ID, of the image I just uploaded to the images section of my schema when the user hits submit on the creation of an article. I've tried doing a readstream on submit, but again, the problem is I can't get the ID, or the filename, to be able to associate it.
They are getting stored in the mongo database, it creates fs.files and fs.chunks, but for the life of me I can't figure out how to get that data and attach it to a schema, or just even get the data out, without knowing the ObjectId.
So how do I call out the objectid from fs.files or fs.chunks to attach it to the schema? and in the schema how do I reference the fs.files or chunks? so it knows what the objectid is associated with?
I can provide anymore data, if what I have is to vague, I have a nasty habit of doing that. sorry.
So I ended up solving my problem, might not be the best solution, but it works until I can get a better solution.
in the API changed
res.status(200).json({"id":readStream.id});
to
res.status(200).send(readStream.id);
in my component, I then set the state to the response.body, which will set the state of the id of the image uploaded. So in the main view, i reference the image uploading component, and set the image state of my view to the id state of my component, and viola, I now have the id in my database, associated with the newly created article.
the problem i then ran into was, it didn't know what to reference. so I attached the API URL to the id, and it acts like it is referencing a URL img, and renders the image correctly.
Again, this may not be the best way to go about this, in fact, I am pretty sure it isn't, but It is whats working for now until I can either reference the database correctly, or create a new component that just stores all the images on server and reference them that way, much like wordpress.

Mongodb multiple refrence to same field

I want to use refrence of multipe collection on the same field of mongodb mongoose schema. Is this possible?? All I want is to save object id of different collection in same field,I am doing this,but its not working correctly..
var QuizSchema = new Schema({
goal_id:{
type: Schema.ObjectId,
ref: 'Exam'||'Subject',
}
});
here its save data properly..but when I use populate method it returns null value for document which has ref to second collection ie. Subject
Even if you are able to register a reference to both Models, how do you think Mongoose will be able to populate it?
Instead, you can simply have references to both:
var QuizSchema = new Schema({
goal:{
exam: {type:ObjectId, ref:'Exam'},
subject: {type: ObjectId, ref: 'Subject'}
}
});
This will even make it convenient to read after population.

Compund index which overwrites previous document

I am trying to create a model for MongoDb using mongoose where I want to ensure that only one document exists for a particular user and file.
var FileStatusSchema = new mongoose.Schema ({
file: mongoose.Schema.Types.ObjectId,
user: mongoose.Schema.Types.ObjectId,
hasSeen: { type: Boolean, default: false }
})
FileStatusSchema.index = ({file: 1, user: 1}, {unique: true})
Now, if I try to save a document with a combination of file and user which already exists, it raises a duplicate key error.
Is there some way with which I can configure MongoDB to overwrite the document rather than raising an exception?
if document doesn't exists this command will create new one
collection.update({file:2112,user:21421}, {hasSeen:true}, {upsert:true});

Categories