gpt4 book ai didi

node.js - 具有非空字段的 MongoDB/Mongoose 权重记录

转载 作者:可可西里 更新时间:2023-11-01 10:31:07 26 4
gpt4 key购买 nike

我有一个 MongoDB 文档集合。我已经为特定字段分配了权重,但我需要将具有任何非空名称 的记录加权到顶部。我不想按名称排序,我只是希望有名称的记录出现在没有名称的记录之前。

示例模式:

new Schema({
slug: {
type: String,
index: {unique: true, dropDups: true}
},
name: String,
body: {
type: String,
required: true
}
});

示例索引:

MySchema.index({
name:'text',
body:'text'
}, {
name: 'best_match_index',
weights: {
name: 10,
body: 1
}
});

查找查询:

MyModel.find( criteria, { score : { $meta: 'textScore' } })
.sort({ score : { $meta : 'textScore' } })
.skip(offset)
.limit(per_page)

最佳答案

如果我在这里理解你的意思,你的意思是给定这样的文档:

{ "name" : "term", "body" : "unrelated" }
{ "name" : "unrelated", "body" : "unrelated" }
{ "body" : "term" }
{ "body" : "term term" }
{ "name" : "unrelated", "body" : "term" }

正常搜索“术语”会产生如下结果:

{ "name" : "term", "body" : "unrelated", "score" : 11 }
{ "body" : "term term", "score" : 1.5 }
{ "body" : "term", "score" : 1.1 }
{ "name" : "unrelated", "body" : "term", "score" : 1.1 }

但您想要的是将最后一个条目作为第二个条目。

为此,您需要另一个字段的“动态”投影以“加权”,您将在其中使用聚合框架:

MyModel.aggregate([
{ "$match": {
"$text": { "$search": "term" }
}},
{ "$project": {
"slug": 1,
"name": 1,
"body": 1,
"textScore": { "$meta": "textScore" },
"nameScore": {
"$cond": [
{ "$ne": [{ "$ifNull": [ "$name", "" ] }, ""] },
1,
0
]
}
}},
{ "$sort": { "nameScore": -1, "textScore": -1 } },
{ "$skip": offset },
{ "$limit": per_page }
],function(err,results) {
if (err) throw err;

console.log( results );
})

将带有“名称”字段的项目放在没有“名称”字段的项目之上:

{ "name" : "term", "body" : "unrelelated", "textScore" : 11, "nameScore" : 1 }
{ "name" : "unrelated", "body" : "term", "textScore" : 1.1, "nameScore" : 1 }
{ "body" : "term term", "textScore" : 1.5, "nameScore" : 0 }
{ "body" : "term", "textScore" : 1.1, "nameScore" : 0 }

本质上是 $ifNull $cond 内的运算符三元测试是否存在“名称”字段,然后在存在的地方返回 1,在不存在的地方返回 0。

这会传递给 $sort您的排序在“nameScore”上的管道首先将这些项目 float 到顶部,然后是“textScore”。

聚合管道有自己的 $skip 实现和 $limit用于分页。

这与 .find() 实现中的操作集基本相同,包括“匹配”、“项目”、“排序”、“跳过”和“限制”。所以这在处理方式上确实没有区别,只是对结果有更多的控制。

“跳过”和“限制”的使用实际上并不是最高效的解决方案,但有时您会坚持使用它,例如在需要提供“页码”的情况下。但是,如果您可以摆脱它并且只需要向前移动,那么您可以尝试将最后一次看到的“textScore”和“seen_ids”列表跟踪到一定的粒度级别,具体取决于“textScore”值的分布方式是。这些可以作为“跳过”结果的替代方法传入:

MyModel.aggregate([
{ "$match": {
"$text": { "$search": "term" }
}},
{ "$project": {
"slug": 1,
"name": 1,
"body": 1,
"textScore": { "$meta": "textScore" },
"nameScore": {
"$cond": [
{ "$ne": [{ "$ifNull": [ "$name", "" ] }, ""] },
1,
0
]
}
}},
{ "$match": {
"_id": { "$nin": seen_ids }
"textScore": { "$gte": last_score },
}},
{ "$sort": { "nameScore": -1, "textScore": -1 } },
{ "$limit": page_size }
])

这里唯一有点不幸的是 $meta因为 textScore 还不能暴露给初始的 $match操作,这将有助于缩小结果范围,而无需遍历 $project首先。

因此,您实际上无法进行与专门的 $geoNear 之类的事情相同的完整 优化。运算符,但它的文本版本或允许前一个语句会很好。


您在这里可能会注意到,从 .aggregate() 选项返回的对象只是原始 JavaScript 对象,而不是从 等操作返回的 Mongoose“文档”对象。查找()。这是“设计使然”,这里的主要原因是由于聚合框架允许您“操纵”生成的文档,因此这里不能保证这些文档实际上与您最初查询的模式中的文档相同.

由于您并没有真正按照您的预期目的“更改”或“ reshape ”文档,它现在只是退回到您的代码来执行 mongoose 在幕后自动执行的操作并将每个原始结果“转换”为标准的“类型”。

此列表通常应显示您需要执行的操作:

var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;

mongoose.connect("mongodb://localhost/test");

var testSchema = new Schema({
name: String,
body: { type: String, required: true },
textScore: Number,
nameScore: Number
},{
toObject: { virtuals: true },
toJSON: { virtuals: true }
});

testSchema.virtual('favourite').get(function() {
return "Fred";
});

var Test = mongoose.model( "Test", testSchema, "textscore" );

Test.aggregate([
{ "$match": {
"$text": { "$search": "term" }
}},
{ "$project": {
"name": 1,
"body": 1,
"textScore": { "$meta": "textScore" },
"nameScore": {
"$cond": [
{ "$ne": [{ "$ifNull": [ "$name", "" ] }, "" ] },
1,
0
]
}
}},
{ "$sort": { "nameScore": -1, "textScore": -1 } },
],function(err,result) {
if (err) throw err;

result = result.map(function(doc) {
return new Test( doc );
});
console.log( JSON.stringify( result, undefined, 4 ));
process.exit();

});

其中包括输出中的“虚拟”字段:

[
{
"_id": "53d1a9b501e1b6c73aed2b52",
"name": "term",
"body": "unrelelated",
"favourite": "Fred",
"id": "53d1a9b501e1b6c73aed2b52"
},
{
"_id": "53d1ae1a01e1b6c73aed2b56",
"name": "unrelated",
"body": "term",
"favourite": "Fred",
"id": "53d1ae1a01e1b6c73aed2b56"
},
{
"_id": "53d1ada301e1b6c73aed2b55",
"body": "term term",
"favourite": "Fred",
"id": "53d1ada301e1b6c73aed2b55"
},
{
"_id": "53d1ad9e01e1b6c73aed2b54",
"body": "term",
"favourite": "Fred",
"id": "53d1ad9e01e1b6c73aed2b54"
}
]

关于node.js - 具有非空字段的 MongoDB/Mongoose 权重记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24946079/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com