I have a requirement for setting a TTL on a collection of Docs in my app but also need those docs to be referenced by another collection and am unsure how this would work?
Does setting a TTL on a document remove that document from all other reference docs when it is expired or would I have to write a backend process myself and not use mongoDb's TTL indexes?
An example schema of the functionality I would want :
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
createdAt: { type: Date, expires: 60*60*24 },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
So after a Day the Story doc would expire and i would need the ref to that story to expire from the person
You cannot handle this with TTL indexes.
You could use a cron job/scheduled task to remove old documents.
I'd suggest you read this, a nice lightweight way of implementing background processes on MongoDb.
The built-in TTL doc expiration has no support for removing references to expired docs.
You'll need to provide that functionality in your own code if you need it.
Related
I am making a small project in MEAN stack but I can not figure out what data structure to use.
So, in this case, I don't have any reference in the store I just fetch store when a person asks for his or her stores.
var personSchema = Schema({
_id : Number,
name : String,
stores: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
});
var storeSchema = Schema({
_id : Number,
title : String
});
AND:
In this case, I give the store a reference of the person so when a person asks for his or her stores I fetch all the store which has a reference to the person.
var personSchema = Schema({
_id : Number,
name : String
});
var storeSchema = Schema({
_id : Number,
owner : { type: Schema.Types.ObjectId, ref: 'Person' },
title : String
});
Which one is better approach?
First one is better to use as it helps in clean code and queries.
I am creating a web app, where user can create questions. Every time user creates a question a collection should be created, where all the answers to that question should be saved as documents in that collection.
You can use mongodb ORM - mongoose for making your data models like that
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var questionSchema = Schema({
title : String,
text : String,
user : { type: Schema.Types.ObjectId, ref: 'User' },
answers : [{ type: Schema.Types.ObjectId, ref: 'Answer' }]
});
var answerSchema = Schema({
user : { type: Schema.Types.ObjectId, ref: 'User' },
text : String,
});
var Question = mongoose.model('Question', questionSchema);
var Answer = mongoose.model('Answer', answerSchema);
So you will store array of answer ids inside question and can populate data:
Question.findOne().populate('answers').exec(function(err, doc){
console.log(doc.answers) // here populated answers models
})
Also you need describe User model and extend with additional data Question and Answer
I'm building a CRUD-style REST service with Node.js, Express and MongoDB using mongoose. This service is going to allow users of an already existing android application to upload/sync the contents of their individual databases online.
The data model for the already-existing application uses UUIDs (generated in Java) which clashes with the shorter, monotonic MongoDB style _id fields. Because the data model already exists and is populated with data from many users, I cannot convert the source data over to monotonic MongoDB-style _ids. This has left me with 2 options that I can think of: either 1) Make Mongo/Mongoose (or some other ODM) play nicely with full UUIDs instead of the monotonic _ids or 2) add a uuid field to the mongoose model in addition to the _id field and fight the pitfalls of this approach. I'm attempting to choose option #1 and running into issues with ObjectID references.
I originally stumbled upon mongoose-uuid, but unfortunately this isn't working for my use-case properly because it was overwriting my explicitly-set _id value when creating new Mongoose objects. Diving into the plugin code, it assumes that an object is new (by calling checking Mongoose's .isNew value) and thus overwrites the _id with a new uuid. Since I need to retain the original uuid when creating new documents in Mongo, this plugin isn't working for me.
Next, I found a post by Aaron Heckmann, creator of mongoose, on a similar topic. This has been helpful, however I am now encountering the problem where I cannot have my mongoose schemas reference each other by ObjectID, since they technically they are now referencing each other using String `_ids.
Schema example:
var mongoose = require('mongoose');
var uuid = require('node-uuid');
var Schema = mongoose.Schema;
var trackPassSchema = new Schema({
_id: { type: String, default: function genUUID() {
uuid.v1()
}},
//Omitting other fields in snippet for simplicity
vehicle: [
{type: Schema.Types.ObjectId, required: true, ref: 'Vehicle'}
]
});
module.exports = mongoose.model('TrackPass', trackPassSchema);
Referencing schema:
var mongoose = require('mongoose');
var uuid = require('node-uuid');
var Schema = mongoose.Schema;
var vehicleSchema = new Schema({
_id: { type: String, default: function genUUID() {
uuid.v1()
}},
//Omitting other fields in snippet for simplicity
description: {type: String},
year: {type: Number}
});
module.exports = mongoose.model('Vehicle', vehicleSchema);
When I attempt to call save() a trackPass that has been passed in from my application:
var trackPass = new TrackPass(req.body);
//Force the ID to match what was put into the request
trackPass._id = req.params.id;
trackPass.save(function (err) { ... }
I get the following error:
{ [CastError: Cast to ObjectId failed for value "b205ac4d-fd96-4b1e-892a-d4fab818ea2a" at path "vehicle"]
message: 'Cast to ObjectId failed for value "b205ac4d-fd96-4b1e-892a-d4fab818ea2a" at path "vehicle"',
name: 'CastError',
type: 'ObjectId',
value: ["b205ac4d-fd96-4b1e-892a-d4fab818ea2a"],
path: 'vehicle' }
I believe this error makes sense as I'm now using Strings which are longer than typical Mongo ObjectIDs. Without having the ObjectID reference, I don't believe I will be able to populate() referenced objects from other collections. I suppose I could simply not reference the other nested objects in my schema definitions, however I don't like this approach as I feel I will be losing a lot of the benefit of utilizing the ODM. Any other thoughts?
You can still use populate() with _id values of types besides ObjectID, but you do need to use the same type in the reference definition.
So your trackPassSchema would need to change to:
var trackPassSchema = new Schema({
_id: { type: String, default: function genUUID() {
return uuid.v1()
}},
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
As Adam notes in the comments, you could simplify your default value to:
var trackPassSchema = new Schema({
_id: { type: String, default: uuid.v1 },
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
Both JohnnyHK and Adam C answers are correct. But if you're using uuid in schema for an array of objects, it is good to use it like this
var trackPassSchema = new Schema({
_id: { type: String, default: () => uuid.v1 },
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
Because, in one such scenario when i tried using like this _id: { type: String, default: () => uuid.v1 } multiple objects of the array had the same id.
It is not possible in this case as _id is unique field, but it can happen when you are using with fields that aren't unique.
I'm trying to locate a reference to another schema and update a sibling field. Specifically, I'm trying to manipulate the hasResponded field below based on a particular 'survey' ObjectId.
My schema looks like this:
var userSchema = new mongoose.Schema({
// some other stuff
surveys: [{
survey: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Survey'
},
hasResponded: {
type: Boolean,
default: false
}
}]
});
If you have a survey id, simply search for all the users that have this particular id in the array.
Something like that:
Users.find({surveys: { "$elemMatch": { type: <ID> } } });
Then, iterate through the users and their corresponding survey array to find the ones that match the id you gave.
Got to say I would structure this db a little different if this query takes place often.
Make a new Schema - UserSurveys that holds the id of the user and the survey + hasResponded. Like this:
var UserSurveySchema = new mongoose.Schema({
user_id: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
survey_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Survey'}
hasResponded: {type:Boolean, 'default':false}
...
});
You might also want to keep an index on the user and survey ids.
Then, it will be much easier to update the field, requests will take much shorter times.
Hope this helps.
In this example, they create personSchema using ObjectId to reference the Story and this I understand. But then in storySchema why don't they do the same to reference the person?
Or the inverse: why using ObjectId instead of Number in Person?
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Type of reference has to be the same as the referenced schema's _id property.
In case of personSchema it's a Number.
storySchema on the other hand, has the _id field assigned automatically by mongoose - it's not specified in parameters for the schema constructor.
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior