MongoDB,按两个数组之间匹配元素的数量对结果进行排序

Posted

技术标签:

【中文标题】MongoDB,按两个数组之间匹配元素的数量对结果进行排序【英文标题】:MongoDB, sort the results by the number of matching elements between two arrays 【发布时间】:2021-05-16 14:27:48 【问题描述】:

在我的项目中,我使用 MongoDB 作为数据库(特别是用于 typescript 的 mongoose 驱动程序,但这不重要),并且我有一系列遵循此架构的帖子:

export const PostSchema = new Schema(
  author:  type: Types.ObjectId, required: true, ref: 'User' ,
  text:  type: String, required: true ,
  tags: [ type: Types.ObjectId, required: true, ref: 'Tag' ],
  location:  type: PointSchema, required: true ,


export const PointSchema = new Schema(
  type: 
    type: String,
    enum: ['Point'],
    required: true,
  ,
  coordinates: 
    type: [Number],
    required: true,
  ,
  locationName: 
    type: String,
    required: true,
  ,
);

我的问题是是否可以编写一个查询(我认为需要聚合)来返回所有满足条件(例如位置必须在特定距离)的帖子,并按特定的顺序对结果进行排序作为参数传递的标签数组(在我的情况下,数组因用户而异,代表他们的兴趣)。 即选择数组 ["sport", "music", "art"] 为例,我想要一个查询,从数据库中检索所有满足特定条件的帖子(与此问题无关)并排序结果,首先是其标签数组与数组[“sport”,“music”,“art”]共享元素的文档,并且仅在最后没有任何对应关系的文档。 也就是说,像这样:

[

  _id: "507f191e810c19729de860ea",
  tags: ["sport", "art", "tennis"] // 2 matches
,

  _id: "507f191e810c1975de860eg",
  tags: ["sport", "food"] // 1 matches
,

  _id: "607f191e810c19729de860ea",
  tags: ["animals", "art"] // 1 matches
,

  _id: "577f191e810c19729de860ea",
  tags: ["animals", "zoo"] //0 matches

]

【问题讨论】:

【参考方案1】:

如果您的收藏看起来像这样:

[
    
        "author": "John",
        "tags": [
            ObjectId("60278ce8b370ff29b83226e2"), // Sport
            ObjectId("60278ce8b370ff29b83226e8"), // Music
            ObjectId("60278ce8b370ff29b83226e5"), // Food
        ]
    ,
    
        "author": "Dheemanth",
        "tags": [
            ObjectId("60278ce8b370ff29b83226e7"), // Tech
            ObjectId("60278ce8b370ff29b83226e5"), // Food
            ObjectId("60278ce8b370ff29b83226e2")  // Sport
        ]
    ,
    
        "author": "Niccolo",
        "tags": [
            ObjectId("60278ce8b370ff29b83226e2"), // Sport
            ObjectId("60278ce8b370ff29b83226e8"), // Music 
            ObjectId("60278ce8b370ff29b83226e3")  // Art
        ]
    
]

那么这就是解决方案:

db.posts.aggregate([
  
    $lookup: 
      from: "tags",
      let:  "tags": "$tags" ,
      pipeline: [
        
          $match: 
            $expr:  $in: ["$_id", "$$tags"] 
          
        
      ],
      as: "tags"
    
  ,
  
    $addFields: 
      "tagCount": 
        $size: 
          $filter: 
            input: "$tags",
            as: "tag",
            cond:  $in: ["$$tag.name", ["sport", "music", "art"]] 
          
        
      
    
  ,
  
    $sort:  tagCount: -1 
  ,
  
    $project: 
      _id: 1,
      tags: "$tags.name"
    
  
])

输出:

[
  
    "_id": ObjectId("60278e14b370ff29b83226eb"),
    "tags": ["sport", "art", "music"]
  ,
  
    "_id": ObjectId("60278e14b370ff29b83226e9"),
    "tags": ["sport", "food", "music"]
  ,
  
    "_id": ObjectId("60278e14b370ff29b83226ea"),
    "tags": ["sport", "food", "tech"]
  
]

【讨论】:

完美运行!非常感谢,你拯救了我的一天!至于效率,您认为这是一个可以接受的大规模操作吗?

以上是关于MongoDB,按两个数组之间匹配元素的数量对结果进行排序的主要内容,如果未能解决你的问题,请参考以下文章

Javascript => 按日期相互匹配数组元素

MongoDB 实用数组聚合操作 (2)

mongodb 查询求助,嵌套数组里面查东西

MongoDB按数组中的元素分组

mongodb - 如果数组中的某个元素与查询匹配,则忽略文档

在Python中计算两个不同数字中连续匹配元素的数量