Mongoose - reference an embedded id in the parent document - node.js

I have this simple schema so far:
var room = new Schema(
{
name: { type: String, default: null, trim: true }
});
var event = new Schema({
name: { type: String, default: null, trim: true },
startDate: Date,
endDate: Date,
logo: { type: Boolean, default: false },
public: { type: Boolean, default: false },
rooms: [room]
sessions: [
{
title: { type: String, default: null, trim: true },
description: { type: String, default: null, trim: true },
date: Date,
start: Number,
end: Number,
room: { type: Schema.Types.ObjectId, ref: 'room' }
}
]
});
I know how to reference another collection but how do I reference an embedded id in the parent document?
I know this schema is not right because even If I delete a room, the room reference is not removed from a session where it is referenced.
Thanks in advance!

You could create a reference to the event in room schema.Then use the schema.pre middleware to remove the sessions.room value whenever you do a remove on the main parent room.(make sure you remove the eventid from main room schema as well).Also refer Removing many to many reference in Mongoose
var room = new Schema({
name: {
type: String,
default: null,
trim: true
},
eventid: {
type: Schema.Types.ObjectId, //Set reference to event here.
ref: 'event'
}
});
room.pre('remove', function(next) {//event is the schema name.
this.model('event').update({; //this will have all the models,select the event
sessions.room: this._id//will have the room id thats being deleted
}, {
$pull: {
sessions.room: this._id//removes that array from the event.sessions.room
}
}, {
multi: true
},
next();//continues and completes the room.remove.
);
});

Related

Populate returns whole parent document

I just started learning express and mongodb. I recently faced the kind of problem, I'm trying to select all the subdocuments which are inside of Room model.
const books = await Room.find().populate('book');
But it returns whole room document when i want to select only bookings field.
Here's the book schema
const bookSchema = new mongoose.Schema({
startDate: {
type: Date,
required: true,
},
endDate: {
type: Date,
required: true,
},
name: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
},
});
module.exports = mongoose.model("book", bookSchema)
And here's the room schema
const roomSchema = new mongoose.Schema({
currentlyReserved: {
type: Boolean,
default: false,
},
people: {
type: Number,
required: true,
},
roomNumber: {
type: Number,
required: true,
},
pricePerPerson: {
type: Number,
required: true,
},
reservedUntil: {
type: Date,
default: null,
},
reservedBy: {
type: String,
default: null,
},
bookings: {
type: [{ type: mongoose.Schema.Types.ObjectId, ref: "book" }],
},
});
module.exports = mongoose.model("room", roomSchema);
You can project with with second arg to find().
https://docs.mongodb.com/manual/reference/method/db.collection.find/#projection
const books = await Room.find({}, {bookings: 1}).populate('bookings');

mongoose, how to record update_time in sub docs

I have a mongoose schema is:
this is my mongoose schema
'use strict';
module.exports = app => {
const mongoose = app.mongoose;
const custSchema = new mongoose.Schema({
belong: { // 所属信息
user_id: { type: 'String', required: true },
type: { type: 'Number', required: true }, // bee、4s店、平台
username: { type: 'String', required: true }, // 用户名
},
delete: { type: Number, default: 0 },
info: { // 客户基本信息
name: { type: 'String', required: true }, // 客户姓名
brith: { type: 'Date', required: true }, // 出生日期
sex: { type: 'Number', required: true }, // 性别
eduction: Number, // 学历
level: { type: 'Number', required: true }, // 客户等级
tag: Number, // 客户标签
tel: { type: 'Number', required: true }, // 电话
family: { // 家庭信息
situation: Number, // 家庭类型
earning: Number, // 家庭总收入
location: { // 家庭住址
province: Number, // 省
city: Number, // 市县
region: Number, // 区镇
addr: String, // 具体地址
},
},
job: { // 工作信息
industry: Number, // 行业
company: String, // 公司
occupation: String, // 职位
earning: Number, // 收入
location: { // 公司地址
province: Number, // 省
city: Number, // 市县
region: Number, // 区镇
addr: String, // 具体地址
},
},
comment: String, // 备注
update_time: { type: 'Date', required: false }, // 数据更新时间
},
... other code
how to save update_time when I update a field in 'custSchema.info'?
such as: I want to update 'info.name', after that, a update_time in 'cust.schema.info' will be included.
I don't prefer to solve this question by add logic on Service, Can I solve it by defining schema?
Yes, you can! Actually, this is a common issue, there are several plugins to help you, my recommendation is: Mongoose Timestamp.
https://github.com/drudge/mongoose-timestamp
It is very simple, a single file, you can actually read it before integrating into you project directly on Github.
Then, you can use the timestamps as follows:
User.findOneAndUpdate({username: 'Prince'}, { password: 'goatcheese' }, { new: true, upsert: true })
.exec(function (err, updated) {
console.log(user.updatedAt); // Should be approximately createdAt + 1 second
console.log(user.createdAt < user.updatedAt); // true
});

How to select a value from an array in mongoose schema

Using MongoDb version 3.2.7
I have a mongoose schema like this which has an array of stock in branch schema. I want to select a subCategoryId in stock array and get the currentPrice of that subCategoryId only, for that I am using query
var getCriteria = { "stock.subCategoryId": subCategoryId }
var update = { "stock.$.currentPrice": currentPrice }
This query works for me at the time of updating the value as I am able to update the currentPrice of selected subCategoryId perfectly. But when I want to get a price of particular subCategoryId the following query gets me all the stocks in the branch collection. The query I am using is this:
var getCriteria ={ "stock.subCategoryId": subCategoryId }
Mongoose Schema
var branch = new Schema({
branchName: { type: String, trim: true, index: true, default: null },
isBlocked: { type: Boolean, default: false, required: true },
email: { type: String, trim: true, required: true, unique: true, index: true },
password: { type: String, required:true },
accessToken: { type: String, trim: true, index: true, unique: true, sparse: true },
stock: [stock],
});
var stock = new Schema({
categoryId: { type:Schema.ObjectId, ref: "categoies", default: null },
subCategoryId: { type:Schema.ObjectId, ref: "subCategories", default: null },
currentPrice: { type: Number },
isBlocked: { type: Boolean, default: false, required: true },
Date: { type: Date, default: Date.now, required: true }
});
To retrieve only the matching array element try this:
branch.find(getCriteria,{'stock.$' : 1},function(err,branch){...});
stock.$ will help you to retrieve only the matched element from the array.

How to write update query in mongodb for deeply nested array?

Hi I have a Model Customer and its schema
var customerSchema = new Schema({
name: {type: String, required:true, trim: true, index: true, default: null, sparse: true},
cardInfo: { type: [cardInfoSchema]}
})
var cardInfoSchema = new Schema({
customerId : { type: String, required: true, index: true, unique: true,trim : true, sparse: true},
cards: { type:[cardsSchema], default:[]}
}, {_id: false});
var cardsSchema = new Schema({
cardType : { type: String, required: true, default: null, trim : true },
isActive : { type: String, required: true, trim: true }, //0: not active, 1: active
cardId : { type: String, required: true, trim: true },
createdAt : { type: Date, default: Date.now, required: true }
})
I want to add multiple cards of customer so I am using this
var dataToSet = {
'cardInfo.customerId': '25934285649875',
$push: {
'cardInfo.cards': {
cardId: 'somecardid,
cardType: 'type',
createdAt: new Date().toISOString(),
isActive: true
}
}
};
But I am getting this error.
cannot use the part (cardInfo of cardInfo.customerId) to traverse the element ({cardInfo: []})
Please help me in writing the query to add card of customer using mongodb or mongoose.
Try the positional $ operator in your update which acts as a placeholder for the first element that matches the query document, and when you use it make sure the cards array field must appear as part of the query document. In your case you'd want to add a card document into the 'cards' array, but only if the cardId doesn't exist:
var query = {
"cardInfo.cards.cardId": { "$nin": ["somecardid"] }
};
var update = {
"$push": {
"cardInfo": { "customerId": "25934285649875" },
"cardInfo.$.cards": {
cardId: "somecardid",
cardType: "type",
createdAt: new Date().toISOString(),
isActive: true
}
}
};
Customer.update(query, update, function (err, result) { ... });

one to many relationship in mongoose

I'm using mean stack to create a hybrid app.I'm using nosql to create DB in mongoose.My DB consists of two tables one is 'donors' and another one is 'bloodGroup'.
My 'bloodGroup' schema is as follows:
module.exports = function(mongoose) {
var Schema = mongoose.Schema;
/* bloodGroup Schema */
var bloodGroupSchema = new Schema({
name: { type: String, required: true }
});
}
My 'Donor'schema is as follows:
/* Donor Schema */
var DonorSchema = new Schema({
Name: { type: String, required: true },
DOB: { type: Date, required: true, trim: true },
Sex: { type: String },
BloodGroupID: { type: Schema.Types.ObjectId, ref: 'BloodGroup', required: true },
ContactNo: { type: String, required: true },
LocationId: { type: Schema.Types.ObjectId, ref: 'Location', required:true },
EmailId: { type: String, required: true },
Password: { type: String, required: true }
});
When many donors refer to a single blood group then BloodGroup object Id error is reported.How to solve this problem?
You can refer this link for documentation: http://mongoosejs.com/docs/populate.html
Saving Refs
/* Donor Schema */
var DonorSchema = new Schema({
_id : {type: Number},
Name: { type: String, required: true },
DOB: { type: Date, required: true, trim: true },
Sex: { type: String },
BloodGroupID: { type: Schema.Types.ObjectId, ref: 'BloodGroup', required: true },
ContactNo: { type: String, required: true },
LocationId: { type: Schema.Types.ObjectId, ref: 'Location', required:true },
EmailId: { type: String, required: true },
Password: { type: String, required: true }
});
/* bloodGroup Schema */
var bloodGroupSchema = new Schema({
_bid :{ type: Number, ref: 'Donor' },
name: { type: String, required: true }
});
module.exports = mongoose.model('Donor', DonorSchema);
module.exports = mongoose.model('Blood', bloodGroupSchema);
var vidya = new Donor({ _id: 0, name: 'Vidya', sex: 'F' });
vidya.save(function (err) {
if (err) return handleError(err);
var blood = new BloodGroup({
name: 'B+',
_bid: vidya._id // assign the _id from the Donor
});
blood.save(function (err) {
if (err) return handleError(err);
// thats it!
});
});
Mongo is not a Relational database, relation one to many does not exist in mongDB. The question is quite confusing, but following the title, you should either embed the donnors into the BloodGroup, or create an Id field unique to which you will refer and do two queries.

Resources