Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB/Mongoose使用查找、嵌套数组和排序聚合_Mongodb_Mongoose_Aggregation Framework - Fatal编程技术网

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
    将保持不变
  • 因此,在第11步结束时,我们将使用保存的日期填充和排序所有带有
    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实现什么