node.js - Mongoose - 根据分数或权重在三个字段中搜索文本

标签 node.js mongodb mongoose mongodb-query

我在 MongoDB 上使用 Mongoose。这就是我的模型的样子。

var BookSchema = new Schema({
  name: String,
  viewCount: { type: Number, default: 0 },
  description: {
    type: String,
    default: 'No description'
  },
  body: {
    type: String,
    default: ''
  }
    }
});

我需要在 Name, Description, Body 上搜索一些文本字段。到目前为止,这就是我正在做的事情及其工作原理:

Book.find().or([{ 'name': { $regex: term, $options: "$i" }}, { 'description': { $regex: term, $options: "$i" }}, { 'body': { $regex: term, $options: "$i" }}]).exec(
    function (err, topics) {
      if (err) {
        return handleError(res, err);
      }
      return res.status(200).json(books);
    });

问题:我需要想出一些机制,用 Name,Description,Body 将权重/分数分配给所有字段( name )权重最高,description权重略低于名称和 body权重最小。当结果出来时,我想按分数/权重对结果进行排序。

到目前为止,我已经研究过这个 link & weights ,但不确定获得所需结果的最佳方法是什么。我还想了解,我是否需要在每次搜索之前创建权重,或者它是一次性事件以及如何使用 Mongoose 实现权重?

最佳答案

一个"text index"search只要您搜索整个单词,这确实可能是最好的选择。

将文本索引添加到架构定义中非常简单:

BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)

这允许您通过“设置”字段权重来执行简单搜索:

Book.find({ "$text": { "$search": "Holiday School Year" } })
    .select({ "score": { "$meta": "textScore" } })
    .sort({ "score": { "$meta": "textScore" } })
    .exec(function(err,result) {

    }
);

每个匹配的术语将根据它所在的字段进行考虑,该字段给出了最大的权重和出现次数。

权重的分配是附加在“索引”上的,因此定义一旦完成就无法更改。另一个限制是“文本搜索”不查看“部分”单词。例如,“ci”与“City”或“Citizen”不匹配,为此您需要一个正则表达式。

如果您需要更多的灵活性,或者通常必须能够动态更改结果的权重,那么您需要聚合框架或 mapReduce 之类的东西。

但是聚合框架无法执行"logical" match将“正则表达式”操作(它可以通过 $match 运算符进行过滤,但不能进行“逻辑”匹配)。如果适合的话,您可以使用单个单词和“精确”匹配。

Book.aggregate(
    [
        { "$match": {
            "$or": [
                { "name": /Holiday/ },
                { "description": /Holiday/ },
                { "body": /Holiday/ }
            ]
        }},
        { "$project": {
            "name": 1,
            "description": 1,
            "body": 1,
            "score": {
                "$add": [
                    { "$cond": [{ "$eq": [ "$name", "Holiday" ] },5,0 ] },
                    { "$cond": [{ "$eq": [ "$description", "Holiday" ] },2,0 ] },
                    { "$cond": [{ "$eq": [ "$body", "Holiday" ] },1,0 ] }
                ]
            }
        }},
        { "$sort": { "score": -1 } }
    ],
    function(err,results) {

    }
)

由于聚合管道使用数据结构来查询,您可以在其中将每次执行的权重参数更改为您当前需要的任何内容。

MapReduce 具有类似的原理,您可以在作为前导元素发出的主键的一部分中包含计算出的“分数”。 MapReduce 会自然地对该键发出的所有输入进行排序,作为馈送到归约函数的优化。但是您无法进一步排序或“限制”这样的结果。

这些通常是您查看并决定最适合您情况的选项。

关于node.js - Mongoose - 根据分数或权重在三个字段中搜索文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32063998/

相关文章:

javascript - 为什么 Node 不作为 Express 的依赖项包含在内?

node.js - 如何在 mongoose/mongodb 中使用不等于运算符?

node.js - bcrypt安装成功后失败

codeigniter - 使用 Codeigniter 进行 MongoDB 切片

javascript - Mongoose保存返回正确的保存对象,但它没有保存到数据库

javascript - mongoose 库需要 json,但无法从 Nodejs 生成动态的

javascript - Node 加密解密最终失败

mongodb - 无法解决 MongoParseError : Invalid connection string

mongodb - 如何使用 docker-compose 存储 MongoDB 数据

node.js - 格式化从 MongoDB/Mongoose group by 返回的对象