MongoDB/Mongoose使用查找、嵌套数组和排序聚合
这些是我的模型MongoDB/Mongoose使用查找、嵌套数组和排序聚合,mongodb,mongoose,aggregation-framework,Mongodb,Mongoose,Aggregation Framework,这些是我的模型 let restaurantSchema = mongoose.Schema({ name: 'string', restId: 'string', saved: {type: 'date', default: Date.now()} }) let userSchema = mongoose.Schema({ firstName: {type: 'string', default: ''}, lastName: {type: 'strin
let restaurantSchema = mongoose.Schema({
name: 'string',
restId: 'string',
saved: {type: 'date', default: Date.now()}
})
let userSchema = mongoose.Schema({
firstName: {type: 'string', default: ''},
lastName: {type: 'string', default: ''},
username: {
type: 'string',
required: true,
unique: true
},
beenTo: [restaurantSchema],
toGoTo: [restaurantSchema]
})
我想做一个提要:“用户a想去餐厅X,用户B想去餐厅Y,用户a去过餐厅Z”,等等,所有这些都主要按日期排序。所以我一直在尝试使用aggregate来生成包含用户名和餐厅名称以及时间戳的文档,这样我就可以对所有文档进行排序,不管用户名是什么,使用{'saved':-1},或者时间戳是什么
这是我到目前为止得到的
User.aggregate([
{$match: {username: {$ne: username}}},
{$lookup: {
from: "restaurants",
localField: "beenTo.saved",
foreignField: "saved",
as: "savRest"
}},
{$project: {'savRest.saved': 1, 'savRest.name': 1, 'username': 1}},
{$group: {
_id: null,
sav: {$push: '$savRest.saved'}
}}
])
考虑到数组,我希望我需要在某个时候$unwind,但我不确定接下来会发生什么…我认为你需要重新构造你的
模式
,在用户文档中只包含餐厅\u id
,而不是将整个餐厅文档
存储为子文档
请将您的userSchema
更改为:
let userSchema = mongoose.Schema({
firstName: {type: 'string', default: ''},
lastName: {type: 'string', default: ''},
username: {
type: 'string',
required: true,
unique: true
},
beenTo: [{type : mongoose.Schema.Types.ObjectId,ref : "Restaurant"}],
toGoTo: [{type : mongoose.Schema.Types.ObjectId,ref : "Restaurant"}]
})
查看我对您的模式所做的更改,我们将只存储其_id(ObjectId),而不是存储餐厅文档
要获取所有餐厅并对其进行排序,您可以执行以下操作:
User.aggregate([
{$match: {username: {$ne: username}}},
// need to unwind the array, before we can do a $lookup over it
{$unwind : "beenTo"},
{$lookup: {
from: "restaurants",
localField: "beenTo",
foreignField: "_id",
as: "beenTo"
}},
//need to unwind again, as $lookup returns an array
{$unwind : "beenTo"},
//sort the result by beenTo.saved (date) first.
{$sort : {"$beenTo.saved" : -1}},
//after sorting, group all the docs and created sorted beenTo array
{
$group : {
_id : "$_id",
firstName : {$first : "$firstName"},
lastName : {$first : "$lastName"},
username : {$first : "$username"},
beenTo : {$push : "$beenTo"},
toGoTo : {$first : "$toGoTo"}
}
},
//after sorting of beenTo, we can go for sorting of toGoTo array,
// we will follow the same procedure again.
{$unwind : "toGoTo"},
{$lookup: {
from: "restaurants",
localField: "toGoTo",
foreignField: "_id",
as: "toGoTo"
}},
//need to unwind again, as $lookup returns an array
{$unwind : "toGoTo"},
{$sort : {"$toGoTo.saved" : -1}},
{
$group : {
_id : "$_id",
firstName : {$first : "$firstName"},
lastName : {$first : "$lastName"},
username : {$first : "$username"},
beenTo : {$first : "$beenTo"}
toGoTo : {$push : "$toGoTo"},
}
}
])
聚合管道说明:
$match
:需要匹配所有选定文档$unwind
:我们需要先解开数组(beenTo
),然后才能对其进行查找$lookup
:从餐厅集合填充受尊重的餐厅文档$unwind
:$lookup
返回一个数组,我们需要再次将其转换为object$sort
:根据beenTo.saved
值对所有文档进行排序$group
:根据用户id对所有文档进行分组,并将所有beenTo
文档推送到其数组中。(现在我们有了用餐厅文档填充的beenTo
数组,并且也进行了排序)$unwind
:接下来我们需要将展开到
数组,以便执行其查找$lookup
:从餐厅集合填充相应的文档$unwind
:我们需要再次展开,因为$lookup
返回一个数组$sort
:根据toGoTo.saved字段对所有文档进行排序$group
:根据用户\u id
对所有文档进行分组,并将所有文档推送到其数组中,而beenTo
将保持不变
beenTo
和toGoTo
的文档
我希望这对你有帮助
注意:在用户文档中将餐馆添加到
beenTo
和toGoTo
数组时,请只推restaurant的id
,而不是完整的doc
,我认为您需要重新构造您的架构,并且只在用户文档中包含餐馆\u id
,而不是将整个餐厅doc
存储为子文档
请将您的userSchema
更改为:
let userSchema = mongoose.Schema({
firstName: {type: 'string', default: ''},
lastName: {type: 'string', default: ''},
username: {
type: 'string',
required: true,
unique: true
},
beenTo: [{type : mongoose.Schema.Types.ObjectId,ref : "Restaurant"}],
toGoTo: [{type : mongoose.Schema.Types.ObjectId,ref : "Restaurant"}]
})
查看我对您的模式所做的更改,我们将只存储其_id(ObjectId),而不是存储餐厅文档
要获取所有餐厅并对其进行排序,您可以执行以下操作:
User.aggregate([
{$match: {username: {$ne: username}}},
// need to unwind the array, before we can do a $lookup over it
{$unwind : "beenTo"},
{$lookup: {
from: "restaurants",
localField: "beenTo",
foreignField: "_id",
as: "beenTo"
}},
//need to unwind again, as $lookup returns an array
{$unwind : "beenTo"},
//sort the result by beenTo.saved (date) first.
{$sort : {"$beenTo.saved" : -1}},
//after sorting, group all the docs and created sorted beenTo array
{
$group : {
_id : "$_id",
firstName : {$first : "$firstName"},
lastName : {$first : "$lastName"},
username : {$first : "$username"},
beenTo : {$push : "$beenTo"},
toGoTo : {$first : "$toGoTo"}
}
},
//after sorting of beenTo, we can go for sorting of toGoTo array,
// we will follow the same procedure again.
{$unwind : "toGoTo"},
{$lookup: {
from: "restaurants",
localField: "toGoTo",
foreignField: "_id",
as: "toGoTo"
}},
//need to unwind again, as $lookup returns an array
{$unwind : "toGoTo"},
{$sort : {"$toGoTo.saved" : -1}},
{
$group : {
_id : "$_id",
firstName : {$first : "$firstName"},
lastName : {$first : "$lastName"},
username : {$first : "$username"},
beenTo : {$first : "$beenTo"}
toGoTo : {$push : "$toGoTo"},
}
}
])
聚合管道说明:
$match
:需要匹配所有选定文档
$unwind
:我们需要先解开数组(beenTo
),然后才能对其进行查找
$lookup
:从餐厅集合填充受尊重的餐厅文档
$unwind
:$lookup
返回一个数组,我们需要再次将其转换为object
$sort
:根据beenTo.saved
值对所有文档进行排序
$group
:根据用户id对所有文档进行分组,并将所有beenTo
文档推送到其数组中。(现在我们有了用餐厅文档填充的beenTo
数组,并且也进行了排序)
$unwind
:接下来我们需要将展开到
数组,以便执行其查找
$lookup
:从餐厅集合填充相应的文档
$unwind
:我们需要再次展开,因为$lookup
返回一个数组
$sort
:根据toGoTo.saved字段对所有文档进行排序
$group
:根据用户\u id
对所有文档进行分组,并将所有文档推送到其数组中,而beenTo
将保持不变
因此,在第11步结束时,我们将使用保存的日期填充和排序所有带有beenTo
和toGoTo
的文档
我希望这对你有帮助
注意:在将餐厅添加到用户文档中的beenTo
和toGoTo
数组时,请只按restaurant的id
,而不是模式中完整的doc
,看起来餐厅是用户文档的子文档,beenTo:[RestaurantSchema]
。这将餐厅文档存储为用户对象的子文档,在这种情况下,$lookup将无法按您所希望的方式工作。如果只想在数组中存储餐厅id,并引用实际的餐厅文档,则需要更改架构:beenTo:[{type:mongoose.schema.Types.Object,ref:'restaurant']
。如果我误解了您的问题,请对其进行编辑以使其更易于理解。这里有点让人困惑。我明白了。如果让人困惑,很抱歉,我自己正在尝试理解其中的大部分内容。在这种情况下,假设我对我的模式进行了建议的编辑,然后我可以得到想要的结果吗?是的,您可以,请告诉我您想要的确切内容你想要什么,我会帮你的。你想用聚合pi实现什么