将 geoQuery 与评级聚合相结合
Combine geoQuery with rating aggregation
我想获取一个半径内的所有对象,以及每个对象的平均评分和总评分。我的两个查询都有效,但我希望将这两个查询合二为一。
位置架构
const LocationObject = new Schema({
name: String
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
required: true
},
coordinates: {
type: [Number],
required: true
}
}
})
ratingSchema
const Rating = new Schema({
locationObject: { type: Schema.Types.ObjectId, ref: 'LocationObject' },
average: Number,
})
位置查询
const objects = await LocationObject.find({
location: {
$geoWithin: {
$centerSphere: [[lon, lat, radius]
}
}
})
单个 LocationObject 的 RatingAggregation
const result = await Rating.aggregate([
{
"$match": {
"locationObject": objectID
}
},
{
"$facet": {
"numbers": [
{
"$group": {
"_id": null,
"totalRating": {
"$sum": "$average"
},
"totalItemCount": {
"$sum": 1.0
}
}
}
],
}
},
{
"$unwind": "$numbers"
},
{
"$project": {
"_id": null,
"avgRating": {"$divide": ["$numbers.totalRating", "$numbers.totalItemCount"]},
"totalRatings": "$numbers.totalItemCount"
}
}
])
最终结果应该 return 一个包含 locationObjects 的数组,每个对象都添加了 average 和 totalRatings。
mongo 操场:https://mongoplayground.net/p/JGuJtB5bZV4
预期结果
[
{
name: String,
location: {
coordinates: [Number, Number],
},
avgRating: Number,
totalRatings: Number
},
{
name: String,
location: {
coordinates: [Number, Number],
}
}
]
根据你最新的 playground,你可以使用 this
db.locationObject.aggregate([
{
"$match": {
"location": {
"$geoWithin": {
"$centerSphere": [
[
6.064953,
52.531348
],
0.0012
]
}
}
}
},
{
"$lookup": { //You need to bring both the collection data together
"from": "Rating",
"localField": "_id",
"foreignField": "locationObject",
"as": "locRatings"
}
},
{
$unwind: "$locRatings"
},
{
"$group": { //you can simplify the other pipelines
"_id": "$_id",
"field": {
"$avg": "$locRatings.average"
},
"totalItemCount": {
"$sum": 1.0
}
}
}
])
要保留文档字段,您需要使用累加器,如 this playground
{
"$group": {
"_id": "$_id",
"field": {
"$avg": "$locRatings.average"
},
"totalItemCount": {
"$sum": 1.0
},
"locations": {
"$addToSet": "$location"
}
}
}
您可以将 empty/null 个数组保留在展开阶段,如下所示
{
$unwind: {
"path": "$locRatings",
"preserveNullAndEmptyArrays": true
}
},
如果需要,您可以添加项目阶段以忽略空值。
我想获取一个半径内的所有对象,以及每个对象的平均评分和总评分。我的两个查询都有效,但我希望将这两个查询合二为一。
位置架构
const LocationObject = new Schema({
name: String
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
required: true
},
coordinates: {
type: [Number],
required: true
}
}
})
ratingSchema
const Rating = new Schema({
locationObject: { type: Schema.Types.ObjectId, ref: 'LocationObject' },
average: Number,
})
位置查询
const objects = await LocationObject.find({
location: {
$geoWithin: {
$centerSphere: [[lon, lat, radius]
}
}
})
单个 LocationObject 的 RatingAggregation
const result = await Rating.aggregate([
{
"$match": {
"locationObject": objectID
}
},
{
"$facet": {
"numbers": [
{
"$group": {
"_id": null,
"totalRating": {
"$sum": "$average"
},
"totalItemCount": {
"$sum": 1.0
}
}
}
],
}
},
{
"$unwind": "$numbers"
},
{
"$project": {
"_id": null,
"avgRating": {"$divide": ["$numbers.totalRating", "$numbers.totalItemCount"]},
"totalRatings": "$numbers.totalItemCount"
}
}
])
最终结果应该 return 一个包含 locationObjects 的数组,每个对象都添加了 average 和 totalRatings。
mongo 操场:https://mongoplayground.net/p/JGuJtB5bZV4
预期结果
[
{
name: String,
location: {
coordinates: [Number, Number],
},
avgRating: Number,
totalRatings: Number
},
{
name: String,
location: {
coordinates: [Number, Number],
}
}
]
根据你最新的 playground,你可以使用 this
db.locationObject.aggregate([
{
"$match": {
"location": {
"$geoWithin": {
"$centerSphere": [
[
6.064953,
52.531348
],
0.0012
]
}
}
}
},
{
"$lookup": { //You need to bring both the collection data together
"from": "Rating",
"localField": "_id",
"foreignField": "locationObject",
"as": "locRatings"
}
},
{
$unwind: "$locRatings"
},
{
"$group": { //you can simplify the other pipelines
"_id": "$_id",
"field": {
"$avg": "$locRatings.average"
},
"totalItemCount": {
"$sum": 1.0
}
}
}
])
要保留文档字段,您需要使用累加器,如 this playground
{
"$group": {
"_id": "$_id",
"field": {
"$avg": "$locRatings.average"
},
"totalItemCount": {
"$sum": 1.0
},
"locations": {
"$addToSet": "$location"
}
}
}
您可以将 empty/null 个数组保留在展开阶段,如下所示
{
$unwind: {
"path": "$locRatings",
"preserveNullAndEmptyArrays": true
}
},
如果需要,您可以添加项目阶段以忽略空值。