I have a User collection and a Task Collection. Many Users can have many Tasks, and Many Tasks can have many Users. The proper way I believe in doing this is the following models:
var UserSchema = new Schema({
id: ObjectId,
username: { type: String, required: true },
assignments: [ {type : mongoose.Schema.ObjectId, ref : 'Assignment'} ]
});
var TaskSchema = new Schema({
id: ObjectId,
title: { type: String, default: '' },
information: { type: String, default: '' },
assignments: [ {type : mongoose.Schema.ObjectId, ref : 'Assignment'} ]
});
var AssignmentSchema = new Schema({
id: ObjectId,
isCompleted: { type: Boolean, default: false },
completionDate: { type: Date, default: null },
tasks: [ {type : mongoose.Schema.ObjectId, ref : 'Task'} ],
users: [ {type : mongoose.Schema.ObjectId, ref : 'User'} ]
});
If the above models are correct, how do you insert a Task with multiple user assignments? I understand that you would create the Task document first to get its ObjectId, but after that would you just insert all of the assignments into the Assignment collection (with their proper Task and User objectId's) and thats it? Or would I have to insert all of the assignments then edit each individual User and Task to insert the AssignmentId into their assignments property.
I am sure there is a stack over flow question like this already, but I have not been able to find one. Any help is appreciated!
I believe you have the answer in your question.
Create a new task, capture the task id. Then find or create a new user, edit or add the task’s id, capture the user id. Add the user id to the task. Repeat for additional users.
I believe this is what you say in the final part of your question?
I don’t see why this cannot work.
Related
Using the model.find method I can find documents that match all properties defined within my schema except when a property has a type of mongoose.Schema.ObjectId. In my case, references to the owner of the document. I've tried all sorts of ways to get documents by the owner _id but nothing is working. Anybody know the proper way to do this ?
--EDIT--
Just in case anybody runs into the same issue, I got it working using the following query.
Query:
const users_cars = await Cars.find( { owner: user_id } );
Schema:
const Schema = new mongoose.Schema({
type: Object,
owner: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [ true, 'car must belong to an owner' ]
},
name: String
});
I have model:
var UserSchema = new Schema({
name : {type: String, required: true},
devices : [
{ uuid : {type: String, required: true},
token : {type: String, required: true}
]
})
When user connects from another (new) device I want to push new device to devices array, otherwise, when user updates token, I need to update existing array item.
So, what I am doing:
User.findOneAndUpdate({name: 'John'}, {
$push: {devices : { uuid : '12345', token : 'TEST_TOKEN'}}
}, {safe: true, new : true}, function(err, user) {
console.log(err);
console.log(user);
});
I think that I need somehow check that device UUID does not exist in array, and if exist update token, otherwise create new device item and push to array
I already try to create uuid index with unique: true
{ uuid : {type: String, required: true, index : {unique: true}}
But this index sets to all collection. And if I have another user with same UUID, I cant add new.
How can I do what I want?
The solution is here, the problem was in that i didnt know how to update arrays in models by using findOneAndUpdate function.
I have 2 moongose Schema:
var Schema2 = new Schema({
creator : { type: String, ref: 'User'},
schema_name : [{ type: String}],
});
var Schema1 = new Schema({
creator : { type: String, ref: 'User'},
schema_ref : [{ type: String, ref: 'Schema2' }],
});
Would like to know which is the best practice when I create a new Schema1 check that every element of array schema_ref, have the same creator.
Because schema1 elements are added by client form and so i have to check that the schema_ref elements are owned by same User that send the form
You can try with either validator function, or with a simple 'save' middleware:
Schema1.pre('save', function(next) {
let owner;
for (let entry in this.schema_ref) {
if (!owner) {
owner = entry;
} else {
if (entry !== owner) {
return next(new Error("owner mismatch");
}
}
}
});
Also, your schema might not work as you expect it to, it looks like you actually need:
schema_ref: [{
type: {type: String},
ref: "User"
}]
Additionally, take a look at id-validator plugin, or some similar to that - it will, in addition to your validation, also check that all ref-type properties like this actually exist in the other (Users) collection.
I have an existing News articles section that I want to add categories to for more refined searching, my Schema's are as follows:
var ArticleSchema = new Schema({
title: String,
body: String,
author: {
type: Schema.Type.ObjectId,
ref: 'User',
required: true
},
image: String,
catagories: [{
type: Schema.Types.ObjectId, ref: 'Catagory'
}],
meta: {
created: {
type: Date,
'default': Date.now,
set: function(val) {
return undefined;
}
},
updated: {
type: Date,
'default': Date.now
}
}
});
ArticleSchema.statics.search = function (str, callback) {
var regexp = new RegExp(str, 'i');
return this.find({'$or': [{title: regexp}, {body: regexp}]}, callback);
};
module.exports = ArticleSchema;
var CatagorySchema = new mongoose.Schema({
name: { type: String, unique: true },
});
module.exports = CatagorySchema;
I want a user friendly input for selecting categories (don't even know what is best here, be it check-box's or a simple comma separated text input etc.). My question is what is the best practice for obtaining this kind of input and translating that into the Article Schema (providing the categories exist). If anyone could point me in the right direction it would be much appreciated. Thanks.
Keep the category names you want to search for in an array
{
categories: ["cat1", "cat2"]
}
then you can add an index to it and do a $in query. the current schema is not very good because you cannot look for the category in a single query but need to resolve all the "categories" links first.
How can I add a schema to another schema? This doesn't seem to be valid:
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String
})
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : UserSchema
})
I checked the website and it shows how to declare it for an array but not for single.
Thanks
There are a few ways to do this. The simplest is just this:
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : Schema.ObjectId
});
Then you just have to make sure your app is writing that id and using it in queries to fetch "related" data as necessary.
This is fine when searching tasks by user id, but more cumbersome when querying the user by task id:
// Get tasks with user id
Task.find({user: user_id}, function(err, tasks) {...});
// Get user from task id
Task.findById(id, function(err, task) {
User.findById(task.user, function(err, user) {
// do stuff with user
}
}
Another way is to take advantage of Mongoose's populate feature to simplify your queries. To get this, you could do the following:
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String,
tasks : [{type: Schema.ObjectId, ref: 'Task'}] // assuming you name your model Task
});
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {type: Schema.ObjectId, ref: 'User'} // assuming you name your model User
});
With this, your query for all users, including arrays of their tasks might be:
User.find({}).populate('tasks').run(function(err, users) {
// do something
});
Of course, this means maintaining the ids in both places. If that bothers you, it may be best to stick to the first method and just get used to writing more complex (but still simple enough) queries.
As of version 4.2.0, mongoose supports single subdocuments.
From the docs:
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});
What about this simple solution?
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
user : {
name : String,
app_key : String,
app_secret : String
}
})