I want to create a DB Schema to store the data as below
{
name : "xyz",
admin : "admin",
expense : [
jan: [{expenseObject},{expenseObject}],
feb: [[{expenseObject},{expenseObject}]
]
}
Expense Object
var expenseSchema = new Schema({
particular : String,
date : {type : Date, default: Date.now},
paid_by : String,
amount : Number
});
Can someone help me create a schema for the same.
Any suggestions for a better Schema for the same concept are welcome.
You can use Sub Docs
var parentSchema = new Schema({
name: { type: String },
admin: { type: String },
expense: [expenseSchema]
});
Or, if you need the expenseObjects to be stored in a seperate collection you can use refs, where Expense would be the name of another model
var parentSchema = new Schema({
name: { type: String },
admin: { type: String },
expense: [{ type: Schema.Types.ObjectId, ref: 'Expense' }],
});
var expenseSchema = new Schema({
particular : String,
date : {type : Date, default: Date.now},
paid_by : String,
amount : Number
});
// your schema
var mySchema = new Schema({
name : {type: String, trim: true},
admin : {type: String, trim: true},
expense: [expenseSchema]
});
--- UPDATE:
With this update now expense is an array of expenseSchema without any categorisation of month. Then if you want to get all expenses in a particular month you can simply do an aggregation like this:
db.users.aggregate(
[
// this match is for search the user
{ $match: { name: "<ADMIN NAME>"} },
// this unwind all expenses of the user selected before
{ $unwind: "$expense" },
// this project the month number with the expense
{
$project: {
expense: 1,
month: {$month: '$expense.date'}
}
},
// this search all the expenses in a particular month (of the user selected before)
{ $match: { month: 8 } },
// this is optional, it's for group the result by _id of the user
//(es {_id:.., expenses: [{}, {}, ...]}. Otherwise the result is a list of expense
{
$group: {
_id:"$month",
expenses: { $addToSet: "$expense"}
}
}
]);
Related
MongoDB documents contain an array of objects and what is the best way to query those documents if I want to find and remove an object from an array with some specific value;
Here is an example of the document schema
const mongoose = require("mongoose");
const LibrarySchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
books: [
{
type: new mongoose.Schema({
bookName: {
type: String,
required: true,
},
chapterReading: {
type: Number,
default: 1,
required: true,
},
}),
},
],
});
const Library = mongoose.model("Library", LibrarySchema);
exports.Library = Library;
If I want to find and remove a book with some bookName
Use $pull
Example :
Library.update({}, { $pull: { books: { bookName: "Yourbookname" } } })
I just asked a related question here:
Mongoose/Mongodb Aggregate - group and average multiple fields
I'm trying to use Model.aggregate() to find the average rating of all posts by date and then by some author's subdocument like country.name or gender. Having trouble with this though. I know for the first stage I just need to use $match for the date and I think I need to use $lookup to "populate" the author field but not sure how to implement this.
This works for finding an average rating for all posts by date:
Post.aggregate([
{ $group: { _id: "$date", avgRating: { $avg: '$rating' }}}
]).
then(function (res) {
console.log(res);
})
And this is basically what I want to do but it doesn't work:
Post.aggregate([
{$match: {"date": today}},
{$group: {_id: {"country": "$author.country.name"}, avgRating: {$avg: "$rating"}}}
]).then(function(res) {
console.log(res)
})
User model:
const userSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
birthday: {
type: Date,
required: true,
},
gender:{
type: String,
required: true
},
country:{
name: {
type: String,
required: true
},
flag: {
type: String,
// default: "/images/flags/US.png"
}
},
avatar: AvatarSchema,
displayName: String,
bio: String,
coverColor: {
type: String,
default: "#343a40"
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post"
}
],
comments: [
{
type: Schema.Types.ObjectId,
ref: "Comment"
}
],
postedToday: {
type: Boolean,
default: false
},
todaysPost: {
type: String
}
})
You can populate an aggregation after you fetched the data from the MongoDB. Your `Query will look a bit like this:
modelName.aggregate([{
$unwind: ''//if Needed
}, {
$group: {
_id: {"country":"$author.country.name"},
avgRating: {
$avg: '$rating'
}
}])
.exec(function(err, transactions) {
// ERRORHANDLING
// CallsBacks
modelName.populate(columnName, {path: '_id'}, function(err, populatedModel) {
// Your populated columnName inside TaleName
});
});
I have the following sub-documents :
{
id: 1,
date:2019-04-01 00:21:19.000
},
{
id: 2,
date:2019-03-31 00:21:19.000
} ...
Document schema is :
const barEventSchema = new Schema({
id: {
type: Number,
unique: true,
required: true
},
raw: { type: String },
date: { type: Date },
type: { type: String },
})
const FooSchema = new Schema({
bar: [barEventSchema]
})
I want to do a query based on a date range picked from html input, which has values like 2019-04-01, 2019-03-31.
So on serverside, I want to do something like:
//#star_date = 2019-04-01, #end_date = 2019-04-01
Foo.findOne('bar.date' : {$lte : start_date, $gte: end_date})
However, this returns all the documents.
All documents having any subdocument with date between start and end date range can be retrieved using:
const conditions = {
'bar': {
$elemMatch: {
'date': {
$gte: new Date(start_date),
$lte: new Date(end_date)
}
}
}
}
Foo.find(conditions)
This will return all the documents where there is at least a subdocument having its date between the range specified in condition.
The $elemMatch operator is used to effect this condition on the date field of the bar subdocument.
var productSchema = Schema({
product_code: String,
name: {
type: String,
required: true
},
description: String,
category:{
type: String,
ref: 'Product_Category'
},
umo: String,
threshold: {
type:Number,
default: 0
},
image: String,
isactive: {
type: Boolean,
default: true
}
});
var product_categorySchema = Schema({
isactive: {
type: Boolean,
default: true
},
name: {
type: String,
required: true
},
description: String
});
I have these two schema I am deleting from category, but if I have data corresponding to that category in product table then that category should not be deleted. Can anyone help?
it should look like something like this :
// Function which delete the category behind the given _id
async function deleteCategory(idCategory) {
// check if there is a product related to the category
const ret = await product_schema.findOne({
category: idCategory,
});
// if there is, return an error
if (ret) throw new Error('Cannot delete the category');
// else do delete the category
return product_category_schema.remove({
_id: idCategory,
});
}
Also you have to know that :
category:{
type: String,
ref: 'Product_Category'
},
is not the right way to setup a reference; it should be an ObjectId not a String
const {
Schema,
} = mongoose;
category:{
type: Schema.Types.ObjectId,
ref: 'Product_Category'
},
Firstly, please update "type" property of "category" field in product schema like this:
category:{
type: Schema.Types.ObjectId,
ref: 'Category' // model name
}`
and declare model like this :
var Product = mongoose.model('Product', productSchema );
then use "distinct" query and "$nin" query-operator to delete category which are not referenced by product schema like this :
Product.find().distinct('category').then((data)=>{
Category.deleteMany({_id: {$nin: data}}).then(del => {
console.log("deleted",del)
})
})
I have user model like this
const guestSchema = mongoose.Schema({
facebook: {
id: String,
token: String,
email: String,
name: String,
phone: String,
dates: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "loginDate"
}
]
}
});
and loginDate model
const loginDateSchema = mongoose.Schema({
loginDate: Date
});
Every time user signs in current Date is added.
How can I find users who have signed in between given date?
I did below but I am getting empty result
Guest.find({ "facebook.id": { $exists: true } })
.populate("facebook.dates")
.find({ "facebook.dates": { $gte: startDate,$lte: endDate } })
.exec((err, foundUsers) => {
res.render("./admin/send", {
facebookUsers: foundUsers
});
});
Sample JSON
{
"_id" : ObjectId("5a1a838f58eb1a50c408de84"),
"facebook" : {
"email" : "sample#yahoo.com",
"name" : "Sample user",
"id" : "12345",
"dates" : [
ObjectId("5a1a838f58eb1a50c408de85"),
ObjectId("5a1a839258eb1a50c408de86"),
ObjectId("5a1a839358eb1a50c408de87"),
ObjectId("5a1a839758eb1a50c408de88"),
ObjectId("5a1aa17058eb1a50c408de8b")
]
},
"__v" : NumberInt(5)
}
LoginDate
{
"_id" : ObjectId("5a1a839358eb1a50c408de87"),
"loginDate" : ISODate("2017-11-26T09:04:19.107+0000"),
"__v" : NumberInt(0)
}
I think the issue is with your date which you are passing into find function on line
.find({ "facebook.dates": { $gte: startDate,$lte: endDate } })
You need to pass a date object and not a date string.
Here is my solution which is working fine for me
Facebook model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
var facebookSchema = new Schema({
id: String,
token: String,
email: String,
name: String,
phone: String,
logindate: Date
},
{
versionKey: false
}
);
module.exports = mongoose.model('Facebook', facebookSchema);
Here is data
[
{
"_id":"5a2949d40591a2192c8fad6b",
"logindate":"2016-10-10T06:28:37.146Z",
"phone":"03006351611",
"name":"mainuhassan",
"email":"mainuhassan#gmail.com",
"token":"MxuXmblL56aqt17aHh1rqcyeHc0E4CwQ",
"id":"100"
},
{
"_id":"5a294cd26c3e661514f3699e",
"logindate":"2015-10-10T06:28:37.146Z",
"phone":"03006351611",
"name":"mainuhassan1",
"email":"mainuhassan1#gmail.com",
"token":"MxuXmblL56aqt17aHh1rqcyeHc0E4CwQ",
"id":"100"
},
{
"_id":"5a294cfe75e2ba2778e9f249",
"logindate":"2017-10-10T06:28:37.146Z",
"phone":"03006351612",
"name":"mainuhassan2",
"email":"mainuhassan2#gmail.com",
"token":"MxuXmblL56aqt17aHh1rqcyeHc0E4CwQ",
"id":"100"
}
]
And here is my code for getting data between dates
Facebook.find({ logindate: { "$gte": new Date("2016-10-10T06:28:37.146Z"), "$lte": new Date("2017-10-10T06:28:37.146Z") } })
.exec(function(error, facebook){
if (!error) {
res.send(facebook);
}
});