如何解决mongoDB中保持ID数组顺序的多对多关系

时间:2018-06-19 11:26:18

标签: mongodb

我在mongoDB上有两个集合poststags。 这些集合之间存在多对多关系。 帖子可以属于某些标签,而标签可以包含一些帖子。

我正在寻找一种有效的查询方法,以将poststags连接起来,并保持postIds的顺序。

如果数据架构不合适,我可以对其进行更改。

mongoDB版本为3.6.5

样本数据

db.posts.insertMany([
  { _id: 'post001', title: 'this is post001' },
  { _id: 'post002', title: 'this is post002' },
  { _id: 'post003', title: 'this is post003' }
])

db.tags.insertMany([
  { _id: 'tag001', postIds: ['post003', 'post001', 'post002'] }
])

所需结果

{
  "_id": "tag001",
  "postIds": [ "post003", "post001", "post002" ],
  "posts": [
    { "_id": "post003", "title": "this is post003" },
    { "_id": "post001", "title": "this is post001" },
    { "_id": "post002", "title": "this is post002" }
  ]
}

我尝试过的

我尝试了一个使用$lookup的查询。

db.tags.aggregate([
  { $lookup: {
      from: 'posts',
      localField: 'postIds',
      foreignField: '_id',
      as: 'posts'
  }}
])

但是我得到的结果与我想要的结果不同。

{
  "_id": "tag001",
  "postIds": [ "post003", "post001", "post002" ],
  "posts": [
    { "_id": "post001", "title": "this is post001" },
    { "_id": "post002", "title": "this is post002" },
    { "_id": "post003", "title": "this is post003" }
  ]
}

2 个答案:

答案 0 :(得分:2)

在MongoDB中,您将尝试对数据建模,以免完全避免联接(例如$lookup中的联接),例如通过将tagsposts一起存储。

db.posts.insertMany([
  { _id: 'post001', title: 'this is post001', tags: [ "tag001", "tag002" ] },
  { _id: 'post002', title: 'this is post002', tags: [ "tag001" ] },
  { _id: 'post003', title: 'this is post003', tags: [ "tag002" ] }
])

有了这种结构,您可以像这样获得所需的结果:

db.posts.aggregate([{
    $unwind: "$tags"
}, {
    $group: {
        _id: "$tags",
        postsIds: {
            $push: "$_id"
        },
        posts: {
            $push: "$$ROOT"
        }
    }
}])

在这种情况下,我会怀疑您是否甚至需要结果中的postIds字段,因为它仍然会包含在posts数组中。

答案 1 :(得分:1)

您可以结合使用$map$filter在投影阶段对posts数组中的元素进行重新排序:

db.tags.aggregate([
    { $lookup: {
          from: 'posts',
          localField: 'postIds',
          foreignField: '_id',
          as: 'posts'
    } },
    { $project: {
        _id: 1,
        postIds: 1,
        posts: { $map: { 
            input: "$postIds", 
            as: "postId", 
            in: {
                $arrayElemAt: [ { $filter: { 
                    input: "$posts", 
                    as: "post", 
                    cond: { $eq: ["$$post._id", "$$postId"] } 
                } }, 0 ] 
            } 
        } }
    } }
])

丢失的帖子将用null填充,以使索引与postIds保持一致。