MongoDB:连接多个数组

dmr*_*r07 5 mongoose mongodb node.js mongodb-query aggregation-framework

我有 3 个数组,ObjectIds我想连接成一个数组,然后按创建日期排序。$setUnion正是我想要的,但我想尝试不使用它。

我想要排序的对象的架构:

var chirpSchema = new mongoose.Schema({
    interactions: { 
      _liked      : ["55035390d3e910505be02ce2"] // [{ type: $oid, ref: "interaction" }]
    , _shared     : ["507f191e810c19729de860ea", "507f191e810c19729de860ea"] //  [{ type: $oid, ref: "interaction" }]
    , _viewed     : ["507f1f77bcf86cd799439011"] //  [{ type: $oid, ref: "interaction" }]
  }
});
Run Code Online (Sandbox Code Playgroud)

期望的结果:将 _liked、_shared 和 _viewed 连接到一个数组中,然后使用aggregate管道按创建日期对它们进行排序。见下文

["507f1f77bcf86cd799439011", "507f191e810c19729de860ea", "507f191e810c19729de860ea", "55035390d3e910505be02ce2"]
Run Code Online (Sandbox Code Playgroud)

我知道我应该使用$push$each$group、 和$unwind以某种组合或其他方式,但我在拼凑文档以实现这一点时遇到困难。

更新:查询

model_user.aggregate([
      { $match    : { '_id' : { $in : following } } }
    , { $project  : { 'interactions' : 1 } }
    , { $project  : {
          "combined": { $setUnion : [ 
            "$interactions._liked"
          , "$interactions._shared"
          , "$interactions._viewed"
        ]}
      }}
])
.exec(function (err, data) {
  if (err) return next(err);
  next(data); // Combined is returning null
})
Run Code Online (Sandbox Code Playgroud)

Bla*_*ven 2

如果所有对象_id值都是“唯一的”,那么这$setUnion是您的最佳选择。当然,它不以任何方式“排序”,因为它与“集合”一起使用,并且不能保证顺序。但您始终可以放松并进行排序。

[
    { "$project": {
        "combined": { "$setUnion": [ 
            { "$ifNull": [ "$interactions._liked", [] ] },
            { "$ifNull": [ "$interactions._shared", [] ] },
            { "$ifNull", [ "$interactions._viewed", [] ] }
        ]}
    }},
    { "$unwind": "$combined" },
    { "$sort": { "combined": 1 } },
    { "$group": {
        "_id": "$_id",
        "combined": { "$push": "$combined" }
    }}
]
Run Code Online (Sandbox Code Playgroud)

当然,由于这是一组不同值,因此在处理每个数组$addToSet后,您可以使用旧方法来代替 , :$unwind

[
    { "$unwind": "$interactions._liked" },
    { "$unwind": "$interactions._shared" },
    { "$unwind": "$interactions._viewed" },
    { "$project": {
        "interactions": 1,
        "type": { "$const": [ "liked", "shared", "viewed" ] }
    }}
    { "$unwind": "$type" },
    { "$group": {
        "_id": "$_id",
        "combined": {
            "$addToSet": {
                "$cond": [
                   { "$eq": [ "$type", "liked" ] },
                   "$interactions._liked",
                   { "$cond": [
                       { "$eq": [ "$type", "shared" ] },
                       "$interactions._shared",
                       "$interactions._viewed"
                   ]}
                ]
            }
        }
    }},
    { "$unwind": "$combined" },
    { "$sort": { "combined": 1 } },
    { "$group": {
        "_id": "$_id",
        "combined": { "$push": "$combined" }
    }}
]
Run Code Online (Sandbox Code Playgroud)

但同样的事情仍然适用于订购。

未来的版本甚至能够连接数组而不减少为“集合”:

[
    { "$project": {
        "combined": { "$concatArrays": [ 
            "$interactions._liked",
            "$interactions._shared",
            "$interactions._viewed"
        ]}
    }},
    { "$unwind": "$combined" },
    { "$sort": { "combined": 1 } },
    { "$group": {
        "_id": "$_id",
        "combined": { "$push": "$combined" }
    }}
]
Run Code Online (Sandbox Code Playgroud)

但仍然无法在不处理$unwind和的情况下对结果重新排序$sort

因此,您可能会认为,除非您需要跨多个文档进行分组,否则基本的“连接和排序”操作最好在客户端代码中处理。目前,MongoDB 无法在数组上“就地”执行此操作,因此客户端代码中的每个文档是您最好的选择。

但是,如果您确实需要对多个文档进行分组,那么此处所示的方法适合您。

另请注意,此处的“创建”是指创建 ObjectId 值本身,而不是引用对象的其他属性。如果您需要这些,那么您可以在聚合或查询之后对 id 值执行填充,当然还可以在客户端代码中进行排序。