I've got the following data structure:
const schema = new Schema({
userId: { type: String, required: true },
image: { type: String, required: true},
name: { type: String, required: true },
description: { type: String, required: true },
subCategories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'SubCategories' }]
}, {
strict: 'throw'
});
export const Plan = mongoose.model('Plan', schema);
const schema = new Schema({
userId: { type: String, required: true },
name: { type: String, required: true },
description: { type: String, required: true }
}, {
strict: 'throw'
});
export const SubCategories = mongoose.model('SubCategories', schema);
and I want to save each of the subCategories in a separate collection each time a new Plan entity is created.
This requires me to iterate the subCategories and to create each one of the sub-category.
for example:
plan.subCategories = await Promise.all(plan.subCategories.map(async (s: IWorkoutDay) => {
const sub = new SubCategories(s);
sub.userId = userId;
await sub.save();
return sub;
}));
const p = new Plan(plan);
p.userId = userId;
await p.save();
and also each time I want to edit the subCategories of the element I'm required to iterate find the element and to update each one separately.
is there an easier way to achieve this? since it seems pretty complicated to me.
Related
May I know how to reference a specific field like in my code is the flowerName? I want to reference flowerName to the inventorySchema from stockSchema. Will this work?
const inventorySchema = ({
id: {type: mongoose.Schema.Types.ObjectId, ref: 'Stocks', required: true},
flowerName: {ref: 'Stocks', required: true},
orderName: {
type: String,
required: true
}
})
module.exports = mongoose.model('Inventory', inventorySchema);
const stockSchema = new Schema({
id: {
type: Number
},
flowerName: {
type: String,
required: true
}
module.exports = mongoose.model('Stocks', stockSchema);
You should reference inventory from stock
const inventorySchema = new Schema({
orderName: {
type: String,
required: true,
},
flowerName: {
type: String,
required: true,
},
});
module.exports = mongoose.model('Inventory', inventorySchema);
const stockSchema = new Schema({
id: {
type: Number
},
inventory: {
type: Schema.Types.ObjectId,
ref: 'Inventory',
required: true
}
});
module.exports = mongoose.model('Stocks', stockSchema);
You should then be able to reference flowerName by populating stock instances with:
const stock = Stocks.findOne({}).populate('inventory').exec();
if (stock) stock.inventory.flowerName
I have an order model/schema, and my goal is that in this model in "list", I receive the information from the model cart in array format. How could I do this using ref?
cart model
const mongoose = require('mongoose');
const CartSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
note: {
type: String,
required: true,
},
price: {
type: Number,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Cart", CartSchema);
order
const mongoose = require('mongoose');
const OrderSchema = new mongoose.Schema(
{
list: {
name: String,
notes: String,
},
totalAmount: {
type: Number,
required: true,
},
payment: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
addressNote: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", OrderSchema);
Basically receive in array format the information of the model cart in "list" in model order
You should define your list as an array of ObjectIds referring to the Cart model:
const OrderSchema = new mongoose.Schema(
{
list: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Cart'
}],
...
});
Then, to retrieve the values in list, just populate the Order:
Order.find({}).populate('list').exec();
Im relatively new to MongoDB and Mongoose. Im much used to MySQL so in used to inner joining tables on calls. Ive read a lot that you can link two Mongoose Schemas to achieve the same outcome. How would like like the two schemas together to when I make a call to get a chore by id it'll return the chore and then for the assignedTo & createdBy have the user scheme data for the said userId?
Chore Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ChoreSchema = new Schema({
title: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
time: {
type: Number,
required: true
},
reaccurance: {
type: [{
type: String,
enum: ['Daily', 'Weekly', 'Bi-Weekly', 'Monthly']
}]
},
reward: {
type: Number,
required: true
},
retryDeduction: {
type: Number,
required: false
},
createdDate: {
type: Date,
default: Date.now
},
createdBy: {
type: String,
required: true
},
dueDate: {
type: Date,
required: true
},
status: {
type: [{
type: String,
enum: ['new', 'pending', 'rejected', 'completed', 'pastDue']
}],
default: ['new']
},
retryCount: {
type: Number,
default: 0,
required: false
},
rejectedReason: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
assignedTo: {
type: String,
required: false,
default: ""
}
});
let Chores = module.exports = mongoose.model('Chores', ChoreSchema);
module.exports.get = function (callback, limit) {
Chores.find(callback).limit(limit);
};
User Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
role: {
type: [{
type: String,
enum: ['Adult', 'Child']
}]
},
birthday: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
balance: {
type: Number,
required: true,
default: 0.00
}
});
let Users = module.exports = mongoose.model('Users', UserSchema);
module.exports.get = function (callback, limit) {
Users.find(callback).limit(limit);
};
Im trying to link ChoreSchema.createdBy & ChoreScheme.assignedTo by UserSchema._id
How I make the call in Node.js:
exports.index = function(req, res) {
Chore.get(function(err, chore) {
if (err)
res.send(err);
res.json({
message: 'Chore List',
data: chore
});
});
};
Mongoose has a more powerful alternative called populate(),
which lets you reference documents in other collections.
https://mongoosejs.com/docs/populate.html
Here is how you can link ChoreSchema.createdBy and ChoreScheme.assignedTo by UserSchema._id
var mongoose = require('mongoose');
const { Schema, Types } = mongoose;
var UserSchema = new Schema({
firstName: { type: String, required: true },
...
})
var ChoreSchema = new Schema({
title: { type: String, required: true },
...
//The ref option is what tells Mongoose which model to use during population
assignedTo: { type: Types.ObjectId, ref: 'Users' },
createdBy: { type: Types.ObjectId, ref: 'Users' },
})
let Chores = mongoose.model('Chores', ChoreSchema);
let Users = mongoose.model('Users', UserSchema);
Then in your express route handler you can populate assignedTo & createdBy like this
router.get('/chores/:id', function (req, res) {
const choreId = req.params.id;
Chores.find({ _id: choreId })
.populate('createdBy') // populate createdBy
.populate('assignedTo') // populate assignedTo
.exec(function (err, chore) {
if(err) {
return res.send(err)
}
res.json({ message: 'Chore List', data: chore });
});
})
I have a field in my mongoose schema called "active" and I wanted to know if there is any way that every date expired in a particular document, then the "active" field would change to false. how should I do that if so, What is the easiest way to do this? else, what is recommended?
And below is my Schema;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const schema = new Schema({
user_id: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
hash: {
type: String,
required: true
},
active: {
type: Boolean,
},
role: {
type: String,
required: true
},
createdDate: {
type: Date,
default: Date.now
}
});
schema.set('toJSON', { virtuals: true });
module.exports = mongoose.model('User', schema);
You can do this with a feature in mongo called Change Streams that allow you to access real-time data changes. You can subscribe to the changes of a single collection or the whole database and react to them. You can also filter for specific changes or transforms. For your case an example would be something like this.
EDIT: Change streams implementation is only available on replica sets.
const pipeline = [
{ $match: { expire_date: {$lt: Date.now()} } },
{ $set: { active: false } }
];
const collection = db.collection('user');
const changeStream = collection.watch(pipeline);
changeStream.on('change', next => {
// process next document
});
I have postSchema which references the tagsSchema.
var tagsSchem = new Schema({
name: {
type: String,
required: true
}
}, {
timestamps: true
});
// create a schema
var postsSchema = new Schema({
title: {
type: String,
required: true,
unique: true
},
mainImage: {
type: String
},
category: {
type: String,
required: true
},
body: {
type: String,
required: true
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
tags: [tagsSchem]
}, {
timestamps: true
});
One post can contain any no. of tags. So if a post has 3 tags then I want to get all the posts with those 3 tags without querying it multiple times. Is it possible?
When you perform find, you can use the $in option to find values that are in your array. For example:
posts.find({tags:{$in:{["tag1","tag2","tag3"]}}, function(err,data) {
... //Your code here
}
This will take all the posts that contains one of the three tags. It's important you have to pass an array in the $in option. This should work.