Compund index which overwrites previous document - javascript

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

Related

Duplicate key error while using _id from another collection

I have 2 collections so far.
The first is a 'Users' collection (That works well), and the other is a 'Rooms' collection (both created for a chat application).
I want every room to have a "users" array that will contain the user._id of every user that is in that room,
meaning I should be able to put the same user._id (from the user collection) in every one of the rooms right?
After creating a room successfully with 2 user._ids in the "users" array,
I tried making another one using one of the user._ids I used in the first room.
Then I got this error:
MongoError: E11000 duplicate key error collection: ratchat.rooms index: users_1 dup key:
{ users: "5fe08d452f34530e641d8f8c" }
After checking with a debugger I've found that the error occurs only when I use a user._id that is already used in another room's "users" array.
The only thing I could think of that could cause this problem is the Room schema,
maybe there's something I missed while reading the docs...
At first my Room schema looked like this:
const roomSchema = new mongoose.Schema({
users: [String],
hasLeft: [String],
isGroup: { type: Boolean, default: false },
},
});
const Room = mongoose.model("Room", roomSchema);
Then I thought maybe mongoDB needs to know that the ObjectIds that are in the users array are just references to another collection:
const roomSchema = new mongoose.Schema({
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
hasLeft: [String],
isGroup: { type: Boolean, default: false },
},
});
const Room = mongoose.model("Room", roomSchema);
No luck so far...
{autoIndex: false}
After research, I have found the reason for this error:
mongoose automatically creates indexes,
this is not only a duplicate error issue, but can cause a significant performance impact later in production.
According to mongoose docs, you can easily disable this behavior by setting the autoIndex option of your schema to false, or globally on the connection by setting the option autoIndex to false.
mongoose.connect('mongodb://user:pass#localhost:port/database', { autoIndex: false });
// or
mongoose.createConnection('mongodb://user:pass#localhost:port/database', { autoIndex: false });
// or
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });
Don't forget to drop the entire collection before trying again
Because the collection is already indexed, emptying it completely won't work.
You have to drop the entire collection.

Mongoose how to update array from child to parent

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.

Refresh Tokens in MongoDB

What is the best solution to remove a refresh token from MongoDB automatically.
On login the user is given a temporary auth token which lasts 30 seconds. They are also given a permanent token, stored in MongoDB, which currently lasts until they log out.
I want to remove the permanent one at the end of every day, but I'm not sure how to do that without having a cron job running (to monitor what time it is). This seems a bit complex for such a small task. Is there a way mongo would know what the time is and then remove the refresh token?
This is how the token collection looks:
Thank you
To auto-delete the MongoDB documents after some time, you should use the TTL(time to live) collection feature documented here.
Essentially, you need to create an index on the collection that stores the token documents. For your use case, you can do something like this:
// This would delete the tokens document after 3600seconds after creation
// You can tweak the time as you wish.
db.tokens.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 3600 });
NodeJS, mongodb.
Just simply create a model for each token.
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const tokenSchema = new Schema({
_userId: {
type: Schema.Types.ObjectId,
required: true,
ref: 'user'
},
token: {
type: String,
required: true
},
expireAt: {
type: Date,
default: Date.now,
index: { expires: 60*60*24 }
}
})
module.exports = mongoose.model('tokens', tokenSchema)

Is it possible to update an Object within a Mongoose document?

I have a weird problem with mongoose, and I'm starting to suspect that I'm doing something wrong.
My schema looks something like this:
var personSchema = mongoose.Schema({
name: String, // Self-e
info: { type: Object, default: {'value':'result'} },
created_on: { type: Date, default: Date.now }
})
After fetching the document, I've tried to edit the info object like so (pretending that person is the fetched document):
person.info['value2'] = 'result2'
person.save()
These changes don't show up in the DB, and I'm getting no errors when running it. Any ideas?
As I learned from #ippi, because info is a mixed Object, you need to make sure that Mongoose knows it was modified so that it will save when you call person.save()
For example:
person.info['value2'] = 'result2'
person.markModified('info')
person.save()

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.

Categories