This question already has answers here:
Automatically remove referencing objects on deletion in MongoDB
(8 answers)
Closed 9 years ago.
With MongoDB and Mongoose, How can I mark objects as dependent on their relations so that if the Parent object is deleted, all of the children objects dependent on it will be deleted as well. For instance, how can I have all articles by an author be automatically deleted if the author is deleted?
var AuthorSchema = new Schema({
created: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
trim: true
}
});
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
content: {
type: String,
default: '',
trim: true
},
author: {
type: Schema.ObjectId,
ref: 'Author'
}
});
If you want to do something like mysql's "foreign key on delete cascade" where if you delete a parent, children are automatically deleted, then it is not possible in pure mongodb.
In order to achieve this, you have to implement it in your application logic. When you delete an author you have to run another delete on the article collection based on the authorID. Do not forget to put an index on this field.
Related
I'm working on an e-commerce project in Express and MongoDB. I'm confused with architecture on how to make relationship between two models such that if I delete one element from a table, all of it's associations should be deleted. CASCADE delete, if I'm using the correct term.
I'm not a database designer, just learning Express and MongoDB. So apologies if my schema is not that good.
I have two tables (or documents in MongoDB). One is Order with schema below:
const orderSchema = new mongoose.Schema({
shippingInfo : {
type: mongoose.Types.ObjectId,
ref: 'Address'
},
user : {
type: mongoose.Types.ObjectId,
ref: 'User',
required: true
},
orderItems: [
{
type: mongoose.Types.ObjectId,
ref:'OrderItem'
}
],
totalPrice: {
type: Number,
required: true,
default: 0.0
},
status: {
type: String,
enum: ['processing', 'shipped', 'delivered','cancelled'],
default: 'processing'
},
deliveredAt: {
type: Date,
}
})
and OrderItems
const orderItemSchema = new mongoose.Schema({
product: {
type: mongoose.Types.ObjectId,
ref: 'Product'
},
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
price: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
})
I want if I delete an Order, all of its OrderItems should be deleted right away (using remove middleware in Order).
I know that Django has something called on_delete=model.CASCADE when we create relationships, but I'm unaware of such thing in Mongoose.
I don't want to explicitly make another API request to search for and delete all OrderItems that are referenced in orderItems array in an Order, once it is deleted. There has to be a better approach for this.
Another post on Stack Overflow suggested that in remove middleware of Order I should do something like
OrderItem.find({ order_id: this._id }).remove().exec();
That would require me to refer order_id in OrderItem right?
And this would create circular dependency since OrderItem would require Order to be created first and vice versa.
What should I do here? Should I change the schema for both tables i.e. remove orderItems entry from Order and instead add order_id in OrderItem? Or is there a Mongoose way to overcome this situation?
I have a schema "Questions" it has like a dozen of questions in it, I can add and delete those questions, I need this collection reflected in a field of other collection - "User" with one additional field (nested in options).
Question Schema:
var QuestionScema = new mongoose.Schema({
key: { type: String, required: true },
label: { type: String, required: true },
name: { type: String, required: true },
page: { type: String, required: true },
type: { type: String, required: true },
options: [{
key: {type: String, required: true},
value: {type: String, required: true}
}],
});
User Schema:
var UserSchema = new mongoose.Schema({
Name: { type: String, required: true },
Email: { type: String, required: true, unique: true },
Password: { type: String, required: true },
//this is where I need to reflect a Questions collection on each user,
//so that it will look something like this//
Questions: [{
key: {type: String, required: true},
//here can be all other fields from Questions collection, that is not a problem
options: [{
key: {type: String, reuired: true},
value: {type: String, reuired: true},
counter: {type: Number, default: 0} //this is the additional field
}]
}],
//
Notifications: [{
Title: { type: String },
Data: { type: String },
Created: { type: Date, default: Date.now }
}]
});
I can't figure out how to do that.
I have another collection of users, say User2 that will answer those questions from Questions collections and I need to keep track on Users schema (not User2, there I just save questions and answers) of how many times an option for that question is chosen.
A Questiuons entry can look like this:
{
key: Haveyouseenthismovie,
label: Have you seen this movie?,
name: Have you seen this movie?,
page: 1,
type: dropdown,
options: [{
key: yes,
value: yes
}, {
key: no,
value: no
}]
}
I want it to work like that (reflect a collection in field of each User) so I don't have to check if that question is in User collection if not add and if it is, is there an option that I need if it is than increment, if not than add that option (that user selected from options in that question in Questions schema) and increment. That looks like a bummer. So I figured that it will be better if that field will reflect a collection and I will just increment the option that I need on a question that I need.
Please help me figure that out, I don't have enough practise in mongo so I struggle with it sometimes :)
I don't think there is a way to reflect a collection in another document as the way you seem to wish it.
As I understand, the following options are available for you:
Embed the entire question document inside the User documents in User Collection.
Just maintain the '_id' of the question document in the User document in User Collection.
Please read on Data Modelling concepts & maintaining relationship between documents from Mongo DB Page https://docs.mongodb.com/manual/applications/data-models-relationships/
This question already has answers here:
MongooseJS cant disable unique to field
(3 answers)
Closed 7 years ago.
My user model looks like:
var UserSchema = new Schema({
name: {
type: String,
unique: false
},
user_url:{
type: String
},
email: {
type: String,
lowercase: true
},
role: {
type: String,
default: 'individual'
},
plan: {
type: String,
default: 'basic'
},
password: String,
provider: String,
salt: String,
facebook: {},
twitter: {},
google: {},
github: {}
});
As you can see, I am trying to allow records with duplicate value in name fields. However when trying to save it throws an error:
Unhandled rejection WriteError({"code":11000,"index":0,"errmsg":"E11000 duplicate key error index: dev.users.$name_1 dup key: { : \"ttp2\" }","op":{"user_url":"ttp2-0","salt":"LY59ooaz+8zZ4z8+dA/7dw==","provider":"local","name":"ttp2","email":"ttp2_1#example.com","password":"wEOc+pejEwfz/s11SWQiMpHxrkh7yLC+q+oa6Tad/QGvH+OFTBMAsVssBRvUKoRjE1dyJkZeh5UvCEJsgXAhNA==","_id":"56b5cc49b6bc872413f6c9fb","__v":0}})
What am I doing wrong?
Presumably, there is still a unique index on the database. If you remove a unique constraint from the mongoose schema which has been defined before, that will not reflect on the database. Simply remove that index directly via the mongodb client.
You can also update your schema programmatically, by putting something like this into your model.js:
mongooseModel.collection.dropIndex('name_of_your_index');
This question already has answers here:
mongoose. updating embedded document in array
(3 answers)
Closed 7 years ago.
I have a nested item schema in an invoice schema as given below :
var InvoiceSchema = new db.Schema({
title: {
type: String,
required: true
},
description: String,
clientId: db.Schema.ObjectId,
companyId: db.Schema.ObjectId,
poNumber: Number,
invoiceNumber: {
type: Number,
default: 1000
},
taxApplied: {
type: Boolean,
default: false
},
feeApplied: {
type: Boolean,
default: false
},
lastUpdated: {
type: Date,
default: Date.now
},
createdOn: {
type: Date,
default: Date.now
},
status: {
type: String,
enum: ['presented', 'entered', 'hold', 'paid',
'partially paid', 'reversed', 'void'],
required: true
},
invoiceItems: [InvoiceItemSchema]
});
var InvoiceItemSchema = new db.Schema({
invoiceId: {
type: db.Schema.ObjectId,
required: true
},
description: String,
qty: Number,
rate: Number,
isFlatFee: {
type: Boolean,
default: false
}
});
I am able to create a new invoiceItem and push it directly into the invoice invoiceItems array, and read it when it's in there, but I am having a lot of trouble trying to update and delete. I was looking at this site here
http://tech-blog.maddyzone.com/node/add-update-delete-object-array-schema-mongoosemongodb
But I couldn't seem to get any of that to work.
I know in that blog he is using $set to update things but it looks like it only updates one field and I want to update any field based on user input and not a hard coded field. I don't have any code to show right now because I am quite lost but some help would be appreciated!
If you have a reference to the Invoice from your InvoiceItem you shouldn't really need to save the items in a list in Invoice. If you want to get that list you could simple do a query like:
InvoiceItem.find({invoiceId: invoiceId}, function(err, items) {
...
})
Now this will make it much easier to update as you only need to update each InvoiceItem object and just keep the reference to the Invoice.
Hope this helped you out.
I want to display friends of Authenticated user in angularjs page.
// Find a list of Friends
$scope.find = function() {
$scope.friends = Authentication.user.friends;
$scope.firstFriendName = Authentication.user.friends;
};
I'm using mongoose with nodejs.(MeanJS)
How can I populate friends of current user in meanjs?
Thanks.
Either extend the user object or add a custom model for example Person , that consists of both user reference, and list of friends:
/**
* Person Schema
*/
var PersonSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Person name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
friends:[{
rate: Number,
date: Date
}],
,
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Person', PersonSchema);
Then write the corresponding controller and views. Or just use meanJS generators:
yo meanjs:crud-module Persons
Then add the appropriate changes to the module. By the way, there is a package for something similar that seems to patch the User schema: moongose-friends
var PersonSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Person name',
trim: true
},
desc:{
type: String,
default: '',
trim: true
},
friends:[{
type: Schema.ObjectId,
ref: 'User'
}],
,
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Then you would use the populate() method built into Mongoose which MEANJS uses. You can actually see how this works if you use the generators to build a CRUD module. Then you can look at the express controller for a specific view and you will see how it uses populate() (this is pretty much what you will see for a list function in the express controller when you generate a crud module.
Friends.find().sort('-created').populate('user', 'displayName').exec(function(err, friends) {
// Handle error & return friends code here
});
Hope that helps. You would then want to look at the angular controller and view so that you could modify the object in the controller and reflect it in the view.