I would like that MongoDB clears data from its collections after %seconds pass. I am setting index, but collection doesn't gets cleared after a while, all the documents are still present.
What am I doing wrong?
DB Version: 3.2
Setting Index:
db.collection('history').ensureIndex(
{ '_id': 1, 'created': 1 },
{ unique: true, background: true, w: 1, expireAfterSeconds: 60}
);
// or
db.collection('history').createIndex(
{ '_id': 1, 'created': 1 },
{ unique: true, background: true, w: 1, expireAfterSeconds: 60}
);
// history document
var _history = {
_id: new ObjectId(),
created: new Date()
};
Collection history, index:
var historyCollectionIndex = [
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "guardian_dev.history"
},
{
"v" : 1,
"unique" : true,
"key" : {
"_id" : 1,
"created" : 1
},
"name" : "_id_1_created_1",
"ns" : "guardian_dev.history",
"background" : true,
"expireAfterSeconds" : 60
}
]
Additional question that is connected to creating indexes.
Now, it can happen that two entries have the same created value, and because of this, mongo is now throwing an error of E11000 duplicate key error collection.
Is it possible to add created and expireAfterSeconds, but created doesn't have to be uniq?
According to the MongoDB site:
The TTL index is a single field index. Compound indexes do not support the TTL property.
If you remove the _id: 1 index and instead just use created then it should behave as you expect
According to the documentation, the TTL index is a single field index. Compound indexes do not support the TTL property. You should create the index as follows:
db.collection('history').ensureIndex(
{'created': 1 },
{ unique: true, background: true, w: 1, expireAfterSeconds: 60}
);
I have tested it and this index, unlike the one in your question, clears out the records correctly.
Related
If I have a document with an array of objects.
Document = {
_id: 1,
doc_amount: 0,
subDocsArray: [
{
_id: 1,
amount: 0
},
{
_id: 2,
amount: 1
},
...
]
}
I can increment the doc_amount simply by doing...
Document.updateOne({ _id }, { $inc: { doc_amount: 1} })
But incrementing the amounts in subDocsArray is more tricky. If I have an array of updates for Document.subDocsArray
var newSubDocsArray = [
{
_id: 1,
amount: 5
},
{
_id: 2,
amount: 5
},
]
How would I go about incrementing all amounts in Document.subDocsArray in one call? Bearing in mind that the newSubDocsArray may not always contain every item in subDocsArray so would need to upsert.
Is that even possible?
EDIT:
To clear something up, all the amounts in newSubDocsArray could be different values. Each existing subDoc array item amount should increment by the value of the amount in newSubDocs with the same id.
As I not really answered the question in previous answer, here's a new one.
Afaik, you cannot do this in one call in Mongodb, but you need a call for each new array element. Then you can use arrayFilters to update all your items matching current element. Here's an example with different behaviours :
Your original document :
{
"_id" : 1.0,
"doc_amount" : 0.0,
"subDocsArray" : [
{
"_id" : 1.0,
"amount" : 20.0
},
{
"_id" : 2.0,
"amount" : 31.0
},
{
"_id" : 3.0,
"amount" : 3.0
},
{
"_id" : 5.0
}
]
}
Applying this script :
var newSubDocsArray = [
{
_id: 1,
amount: 3
},
{
_id: 2,
amount: 8
},
{
_id: 4,
amount: 7
},
{
_id: 5,
amount: 9
},
];
newSubDocsArray.forEach(function(newSubDoc){
db.getCollection("test").update(
{_id:1},
{$inc:{"subDocsArray.$[subdoc].amount":newSubDoc.amount}}, // Note the use of $[subdoc]
{ multi: true,
arrayFilters: [ { "subdoc._id": newSubDoc._id } ]
}
)
})
Will result :
{
"_id" : 1.0,
"doc_amount" : 0.0,
"subDocsArray" : [
{
"_id" : 1.0,
"amount" : 23.0 // +3
},
{
"_id" : 2.0,
"amount" : 39.0 // +8
},
{
"_id" : 3.0,
"amount" : 3.0 // unchanged
},
{
"_id" : 5.0,
"amount" : 9.0 // created, set to 9
}
]
}
You can note that :
item with _id 3 is not updated (not in new newSubDocsArray).
item with _id 4 is NOT created in the array (arrayFilters does not match anything).
items with _id 5 has a new amount field created.
You can use the $[] array update oprator to achieve this :
db.getCollection("test").update(
{_id:1},
{$inc:{"subDocsArray.$[].amount":1}}
)
You can updated the sub array item with $ like
give the criteria first { _id: 1,'subDocsArray._id' : 1}
then update items like : {$inc :{'subDocsArray.$.amount':1}}
I have the following userSchema
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var userSchema = new mongoose.Schema({
email: String,
password: String,
userName: String,
fname: String,
lname: String,
userType: Number,
subscribedThreads: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Threads"
}
]
});
// add passport methods
userSchema.plugin(passportLocalMongoose);
// export modules to be used by the file requiring it
module.exports = mongoose.model("Users",userSchema);
The first entry into the collection occurs as it should but the next ones give
{ [MongoError: E11000 duplicate key error collection: KManV3.users
index: username_1 dup key: { : null }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
driver: true,
code: 11000,
index: 0,
errmsg: 'E11000 duplicate key error collection: KManV3.users index:
username_1 dup key: { : null }',
getOperation: [Function],
toJSON: [Function],
toString: [Function]
}
Also, dbname.users.getIndexes() gives:
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "KManV3.users"
},
{
"v" : 1,
"key" : {
"password" : 1
},
"name" : "password_1",
"ns" : "KManV3.users",
"background" : true
},
{
"v" : 1,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "KManV3.users",
"background" : true
}
]
Apparently every property of schema has been set as unique and I can't add data into collections even if the data is totally different. I'm not sure if it's due to integration of passport.
Looking at the options for passport-local-mongoose:
usernameField: specifies the field name that holds the username. Defaults to 'username'.
usernameUnique : specifies if the username field should be enforced to be unique by a mongodb index or not. Defaults to true.
Which explains why your collection has a unique index on the (non-existent-in-your-schema) username field.
If you don't actually set this field in documents that you add to the database, MongoDB will use null, and once the first document has been inserted, a subsequent document (also with the field value null for username) will throw an E11000 error.
So first, remove the index on username (and also password, I assume you once marked that field as unique in your schema), and set the proper field name for passport-local-mongoose to use:
userSchema.plugin(passportLocalMongoose, { usernameField : 'userName' });
(or email, if you want that field to be used as unique user identifier)
Error reason - The index is not present in your collection, in which you are trying to insert.
Solution - drop that collection and run your program again.
I have this error i cannot seem to understand what I'm doing wrong.
In my database i have an object called Question, questions have a reference to Subject and to User. When I'm trying to post to Question i get a strange error.
E11000 duplicate key error index: codenoname.questions.$subject.name_1 dup key: { : null }
My Question schema:
var questionSchema = mongoose.Schema({
title: { type : String , required : true},
text: { type : String , required : true},
subject: {type:String, ref: 'Subject', required: true},
createdBy: {type: String, ref:'User', required: true},
difficulty: { type : String , required : true},
alternatives: [{alternative: {type:String, required:true}, isCorrect: {type:Boolean, required:true}}]
});
and my Subject
var subjectSchema = mongoose.Schema({
name: { type : String , required : true, unique:true}
});
Save method:
var question = new Question(
{title: title,
text: text,
subject: ObjectId(subject),
difficulty: difficulty,
createdBy: id,
alternatives:alternatives
});
question.save( function(err, newQuestion) {
if(err) {
res.status(400).json({err:err});
} else {
res.status(200).json({status:"Question added"});
}
});
What i have tried
Delete all Questions, then I can post, but just one...
Remove the reference and just keep it as a string. No difference.
Restarted the server a few times.
Try removing the unique: true from subject. I think questionSchema inherits the unique property and once you try to save two different questions with the same subject, you'll get duplicate key.
Follow these steps:
Remove unique: true from your model
Find the index name by typing db.questions.getIndexes() in your terminal.
Remove it by typing db.questions.dropIndex(name) where name is the "name"-property from step 2
Example from my database where i'll remove the unique-property from usernames:
> db.accounts.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "passport_local_mongoose_express4.accounts"
},
{
"v" : 1,
"unique" : true,
"key" : {
"email" : 1
},
"name" : "email_1",
"ns" : "passport_local_mongoose_express4.accounts",
"background" : true
},
{
"v" : 1,
"unique" : true,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "passport_local_mongoose_express4.accounts",
"background" : true
}
]
> db.accounts.dropIndex('username_1')
So I am trying to do a semi-complicated query in mongoose. It is as follows:
Event.findOne({ users: { $elemMatch: { user: someUserId, going: 1 }, sort: {createTime: -1} } }
Basically what I would like to do is find a single Event that has a user in its user array that matches an Id and is attending. I have multiple user records for each user in the user array so I want to find the most recent one, to do this I would like to sort the user array by createTime. This is where the error is coming in and it just returns undefined. It works just fine when I don't include the sort function, is there any way to include that?
Here is what my Event object looks like:
{
_id: 1,
endTime: 1429060173865,
createTime: 1429051773902,
startTime: 1429052973865,
description: 'some desc',
creator: 2,
users:
[ { user: 1,
status: 1,
going: 1,
createTime: 1429051773749,
_id: 552d997d8e923847306e2c21 },
{ user: 1,
status: 1,
going: 1,
createTime: 1429051773922,
_id: 552d997d8e923847306e2c25 },
{ user: 1,
status: 9,
going: 0,
createTime: 1429051773942,
_id: 552d997d8e923847306e2c26 } ],
destroyed: 0 }
Is there any way to make this query entirely in mongoose?
As part of find, MongoDB can't sort an array field of a document. You could define a virtual of Mongoose to return the array in sorted order. You could also maintain the array in sorted order, as shown below:
> db.test.drop()
// note: not in order when inserted
> db.test.insert({ "_id" : 0, "users" : [
{ "user" : 1, "going" : 1, "created" : 22 },
{ "user" : 2, "going" : 1, "created" : 775 },
{ "user" : 1, "going" : 1, "created" : 6432 }
] })
// insert user to array and sort as part of update
> db.test.update({ "_id" : 0 },
{ "$push" : {
"users" : {
"$each" : [{ "user" : 2, "going" : 1, "created" : 5532 }],
"$sort" : { "created" : -1 }
}
} })
> > db.test.findOne()
{
"_id" : 0,
"users" : [
{ "user" : 1, "going" : 1, "created" : 6432 },
{ "user" : 2, "going" : 1, "created" : 5532 },
{ "user" : 2, "going" : 1, "created" : 775 },
{ "user" : 1, "going" : 1, "created" : 22 }
]
}
That way, when you perform your find query, the arrays in the matching documents will already be in the desired order.
Your query is not correctly written. In order to sort you should write it in third argument of find:
Event.findOne(
{ users:
{ $elemMatch: { user: someUserId, going: 1 }}
},
null,
{
sort: {createTime: -1}
},
function(err, event) {
//your event here
});
I have this schema with mongoose
schema = new Schema({
id: {
type: String,
},
embedded: [embeddedSchema]
});
embeddedSchema = new Schema({
value: {
type: String,
},
});
This can produce something like :
{
"_id" : ObjectId("5454f4f1073cc3b529320f79"),
"embedded" : [
{
"value" : 123,
} , {
"value" : 123,
},
{
"value" : 123423,
}
]
}
/* 1 */
{
"_id" : ObjectId("5454f508910ef3b82970f11d"),
"embedded" : [
{
"value" : 1,
} , {
"value" : 2,
},
{
"value" : 9999999,
}]
}
I would like to sort the schema collection by the biggest value of embedded doc.
Which query can produce this kind of result ?
Thanks you!
When you sort descending on an array element field like value, MongoDB uses the maximum value of that field among all elements in the array.
So in this case it would be:
MyModel.find().sort('-embedded.value').exec(callback);