嵌入式文档中的完整文本搜索

Abd*_*eed 9 full-text-search mongodb meteor

这是我的文档模式

"translation" : {
        "en" : {
            "name" : "brown fox",
            "description" : "the quick brown fox jumps over a lazy dog"
        },
        "it" : {
            "name" : "brown fox ",
            "description" : " the quick brown fox jumps over a lazy dog"
        },
        "fr" : {
            "name" : "renard brun ",
            "description" : " le renard brun rapide saute par-dessus un chien paresseux"
        },
        "de" : {
            "name" : "brown fox ",
            "description" : " the quick brown fox jumps over a lazy dog"
        },
        "es" : {
            "name" : "brown fox ",
            "description" : " el rápido zorro marrón salta sobre un perro perezoso"
        }
    },
Run Code Online (Sandbox Code Playgroud)

现在我必须为上面的文档添加文本索引.我怎么能实现?我已经在翻译时添加了文本索引,但由于名称和描述都在语言前缀(在对象内),因此无效.我还必须分别给出名称和描述的文字权重(文本分数).即名称的文本得分为5,描述的得分为2.所以我不能给外卡文本索引即

{'$**': 'text'}
Run Code Online (Sandbox Code Playgroud)

我也尝试过,'translation.en.name': 'text'但是没有工作,而且我的语言也是动态的,因此增加了这个案例的最佳解决方案

任何帮助将不胜感激.

chr*_*dam 5

由于嵌入字段是动态的,因此最好的方法是修改模式,使translation字段成为嵌入文档的数组.映射当前结构的此类模式的示例如下:

"translation": [    
    {
        "lang": "en",
        "name" : "brown fox",
        "description" : "the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "it",
        "name" : "brown fox ",
        "description" : " the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "fr",
        "name" : "renard brun ",
        "description" : " le renard brun rapide saute par-dessus un chien paresseux"
    },
    {
        "lang": "de",
        "name" : "brown fox ",
        "description" : " the quick brown fox jumps over a lazy dog"
    },
    {
        "lang": "es",
        "name" : "brown fox ",
        "description" : " el rápido zorro marrón salta sobre un perro perezoso"
    }
]
Run Code Online (Sandbox Code Playgroud)

使用此模式,可以轻松地在namedescription字段上应用文本索引:

db.collection.createIndex(
    {
        "translation.name": "text",
        "translation.description": "text"
    }
)
Run Code Online (Sandbox Code Playgroud)

至于修改架构,您需要使用api,它允许您批量更新集合,并Bulk API为您执行此操作.这些提供了更好的性能,因为您将以1000个批次的形式将操作发送到服务器,这样可以提供更好的性能,因为您不是将每个请求发送到服务器,而是每1000个请求中只发送一次.

以下演示了此方法,第一个示例使用MongoDB版本中的Bulk API> = 2.6和<3.2.它通过将所有翻译字段更改为数组来更新集合中的所有文档:

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

db.collection.find({ 
    "translation": { 
        "$exists": true, 
        "$not": { "$type": 4 } 
    } 
}).snapshot().forEach(function (doc) {
    var localization = Object.keys(doc.translation)
        .map(function (key){
            var obj = doc["translation"][key];
            obj["lang"] = key;
            return obj;
        });
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "translation": localization }
    });

    counter++;
    if (counter % 1000 === 0) {
        bulk.execute(); // Execute per 1000 operations 
        // re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp(); 
    }
})
// Clean up remaining operations in queue
if (counter % 1000 !== 0) { bulk.execute(); }
Run Code Online (Sandbox Code Playgroud)

下一个示例适用于新的MongoDB版本3.2,后者已弃用批量API并提供了一组较新的apis bulkWrite().

它使用与上面相同的游标,但使用相同的forEach()游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组.因为写入命令可以接受不超过1000次操作,所以您需要将操作分组以包含最多1000次操作,并在循环达到1000次迭代时重新初始化该数组:

var cursor = db.collection.find({ 
        "translation": { 
            "$exists": true, 
            "$not": { "$type": 4 } 
        } 
    }).snapshot(),
    bulkUpdateOps = [];

cursor.forEach(function(doc){ 
    var localization = Object.keys(doc.translation)
        .map(function (key){
            var obj = doc["translation"][key];
            obj["lang"] = key;
            return obj;
        });
    bulkUpdateOps.push({ 
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": { "$set": { "translation": localization } }
         }
    });

    if (bulkUpdateOps.length === 1000) {
        db.collection.bulkWrite(bulkUpdateOps);
        bulkUpdateOps = [];
    }
});         

if (bulkUpdateOps.length > 0) { db.collection.bulkWrite(bulkUpdateOps); }
Run Code Online (Sandbox Code Playgroud)