I have 2 collections one is user and other is college. I want a rating schema with aggregate query user 1 gives 2 rating to college 1
I made a rating schema like
rate = mongoose.Schema({
rating: number,
userId:
collegeid:})
college comes on the basis of score user gets. And then user is allowed to rate the colleges, he has been shown.
So how to write the query to fetch the rating. How can I achieve this?
Let's assume the rate collection has data like this:
var r = [
{ rating: 1, userId: "U1", collegeid: "C1" },
{ rating: 1, userId: "U1", collegeid: "C2" },
{ rating: 3, userId: "U1", collegeid: "C3" },
{ rating: 2, userId: "U2", collegeid: "C1" },
{ rating: 6, userId: "U2", collegeid: "C2" },
{ rating: 7, userId: "U3", collegeid: "C1" },
{ rating: 5, userId: "U3", collegeid: "C4" },
{ rating: 3, userId: "U3", collegeid: "C3" }
];
Here are some useful queries to get started. In general, aggregate() is The New find() (since at least v3.2) and although slightly more complicated for the simplest expressions, it is vastly more powerful and it should be your starting point.
// Lookup all ratings available for collegeid C1:
c=db.rate.aggregate([
{$match: {"collegeid":"C1"}}
]);
// Lookup all ratings by user U3:
c=db.rate.aggregate([
{$match: {"userId":"U3"}}
]);
// Lookup all ratings by user U3 for college C1:
c=db.rate.aggregate([
{$match: {"userId":"U3","collegeid":"C1"}}
]);
// Lookup all ratings by user U3 OR college C1:
c=db.rate.aggregate([
{$match: {$or: [
{"userId":"U3"},
{"collegeid":"C1"}
]}}
]);
// Get counts, avg, max & min ratings for all colleges:
c=db.rate.aggregate([
{$group: {_id:"$collegeid", n:{$sum:1},
avg:{$avg:"$rating"},
max:{$max:"$rating"},
min:{$min:"$rating"}}}
]);
// Who rated colleges the highest?
c=db.rate.aggregate([
{$sort: {"rating":-1}}, // sort descending
// Use $first operator to capture only the first item for each unique collegeid
// in the sorted material flowing into this stage:
{$group: {_id:"$collegeid", who:{$first:"$userId"}, rating:{$first:"$rating"} }}
]);
You can use the built-in mongoose populate function if you define your Schema correctly.
Please check the link below
https://mongoosejs.com/docs/populate.html
The "mongoose" way would look something like
ratingSchema = mongoose.Schema({
rating: Number,
userId: {
ref: 'users', // Name of the collection that you would like to link to
type: mongoose.SchemaTypes.ObjectId // I Just added the object ID type you could use
// a string or whatever your id is
},
collegeId: {
ref: 'colleges', // Name of the collection that you would like to link to
type: mongoose.SchemaTypes.ObjectId
},
})
const Rating = mongoose.model('rating', ratingSchema);
And then you can use
Rating
.findOne({})
.populate('userId')
.populate('collegeId');
It is good however to read up and learn about the aggregate pipeline, but mongoose can do a lot of heavy lifting for you.
Related
I’m trying to create a filter to manage orders (seller)
orders are composed of "price", "country", "product type",
and seller and customer informations
order: {
_id:""
price: $750
country:"Italy"
customer: objectID
Seller: objectID
productType: "smartphone"
}
customer: {
_id:""
location:"Italy",
paymentType:"paypal"
languages:"it"
}
Seller: {
_id:"278"
location:"UK"
languages:"en"
}
let’s say the seller( _id: 278) wants to find all his orders:
order with a minimum price of $500 and a maximum price of $800
and order in the country "italy" or "belgium"
and order with customers who have paid with "paypal" or "stripe"
and order with customer who speaks English or Italian
So I made this request:
Order.find({ $and:[
seller: 278,
price: {$gte: 500, $lte: 800},
country: { $or:["Italy","belgium"] },
customer: { paymentType: { $or:["paypal","stripe"] },
languages:{ $or:["en","it"] }
]})
and of course I have an error :
" Cast to ObjectId failed for value " paymentType: { $or:["paypal","stripe"]
at path "customer " for model Order"
I don’t know what to put because I’m not targeting any particular customer I don’t need to target client id I don’t understand
Use the $in operator. You don't need $and:
Order.find({
seller: 278,
price: {$gte: 500, $lte: 800},
country: { $in: ["Italy","belgium"] },
"customer.paymentType": { $in: ["paypal","stripe"] },
languages:{ $in: ["en","it"] }
})
I have document like below. Here peoples contains array of ObjectId which points to user collection. And contribution field contains as many number of subdocument as peoples field. Length is variable like if some group has 2 ObjectId in people then contribution will have 2 sub document. I need to create mongoDb schema for this, please tell me schema for this.
{
name: "person name",
_id: ObjectId(""),
creater: ObjectId("1"), //referencing to user collection
peoples: [ObjectId("1"), ObjectId("2"),...upto n], //all referencing to user table
contribution: {
ObjectId("1"):{
paid: 1200,
due: 1000,
prevDue: 200,
Advance: 0
},
ObjectId("2"):{
paid: 1200,
due: 1000,
prevDue: 200,
Advance: 0
},
//upto end of lists in peoples array
},
estimated: 30000,
collected: 15379,
left: 14721
}
You just need to reference the nested schema in your main schema. For eg:
let user = new Schema({
name: String
})
let schema = new Schema({
followers: [user]
})
In the followers field of schema, you just referenced the user schema. Whenever this kind of reference is done, the types of nested schema get injected into the reference point.
Here is an implementation. Notice that I defined contribution property as an array of peopleContributionSchema. This makes the collection data easier to be accessed as you can loop for items in that array. The way you implemented is not flexible as ObjectId is a property of contribution, so you would need to know before hand the number of people in the contribution.
var peopleContributionSchema = new Schema({
_id: Schema.Types.ObjectId,
paid: Number,
due: Number,
prevDue: Number,
advance: Number
});
var parentSchema = new Schema({
_id: Schema.Types.ObjectId, // not necessary to define. Mongoose will add by default
name: String,
creater: Schema.Types.ObjectId,
peoples: [Schema.Types.ObjectId],
contribution: [peopleContributionSchema],
estimated: Number,
collected: Number,
left: Number
});
I got it what you want to do but you can't iteration a schema object like an 'n' no of series. An object schema in MongoDB is like key-value pair in JSON Object, you can't iterate it like a loop. Instead, the approach to do that is, define two different schemas and assign one schema in an array to use it in another schema as a subschema.
Follow the below-mentioned code:
{
name: "person name",
_id: ObjectId(""),
creater: ObjectId[1],
peoples: [ObjectId[0], ObjectId[1],...upto n-1],
ObjectId: [
{
paid: 1200,
due: 1000,
prevDue: 200,
Advance: 0
},
{
paid: 1200,
due: 1000,
prevDue: 200,
Advance: 0
}
],
estimated: 30000,
collected: 15379,
left: 14721
}
I am trying to find one product who's id matches given id and also want to know if it's quantity will still be greater or equal to the sold quantity (after adding the sold quantity which will be sold later in the process).
const product = await Product.findOne(
{
$expr: {
$and: [
{ _id: id },
{ $gte: ["$quantity", { $sum: ["$soldQuantity", quantity] }] }
]
}
}
);
(here quantity is a constant who's value is 2 and id is an ObjectId)
what I've achieved so far is if I turn $gte into $lte I get the right result but $gte returns me false result, which should return an empty object instead if conditions did not meet.
I'm using mongoDB version 4.2
Schema has:
Schema({
quantity: {
type: Number,
required: true
},
soldQuantity: {
type: Number,
default: 0
}
})
I need to find documents with Mongoose that contains at least one subdocument, respecting the $elemMatch condition.
My main doc sample is like this:
{
desc: 'Sample',
user: 10,
prices: [{ code: 1, price: 10 }, { code: 2, price: 0 }]
}
I need the documents that contains at least one subdoc with price bigger than 0. If doc no have price bigger than 0, the main doc may be discarded.
With $elemMatch, I can filter the subdocs, but not the main doc:
Prod.find({ user: 10}, { prices: { $elemMatch: { price: { $gt: 0 } } } })
With this, I have the document:
[{
desc: 'Sample',
user: 10,
prices: []
}]
When should it be:
[]
How can I do this?
Hopefully I can explain this well.
I have 3 Model types in play here: Users, Products, and Stores. What I'm after is a sorted list of Stores, per user, based on how many Products they've added from that Store. So basically "show me this User's top Stores".
pseudo-schemas:
var User = {
name: String
};
var Store = {
name: String
};
var Product = {
title: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
}
store: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Store'
}
};
So how can I find which Stores the User has added the most Products to? This may be obvious, it's late. :-P
Thanks!
You can try to use Aggregation framework to solve it.
And especially $group pipeline:
// aggregate whole `Product` collection
Product.aggregate([
// count products by `user` and `store` and save result to `products_count`
{$group: {
_id: {user_id:"$user", store_id:"$store"},
products_count: {$sum: 1}
}},
// sort by most products count
{$sort: {products_count: -1}}
])
There are also $limit and $skip pipelines, that help to paginate all this stuff.