如何检查 MongoDB 数据库中所有 collections 的特定关键字?

How to check all the collections in a MongoDB database for a particular keyword?

我目前正在使用 Mongoose 查询处理 NodeJS 项目。

出现了一个新要求,我无法理解如何解决。我想获取一个查询字符串并在我的数据库的所有 collection 中搜索到 return 匹配该值的 objects。

这是我的 collection 的样子:

书籍:

{
    "book_id": "ab12nld”,
    "book_version": "0”,
    "author": “Sam”,
    “name”: “Sample Book”,
    “comments”: “Done”
  },
  {
    "book_id": "a5g2nld”,
    "book_version": "1",
    "author": "Martin",
    "name": "Sample Book",
    “comments”: “In Progress”
  }

汽车:

{
    "car_id": "nlp240n”,
    "car_model": "3”,
    "brand": “Hyundai”,
    “name”: “Verna”,
    “color”: “Blue”
  },
  {
    "car_id": "cak201n”,
    "car_model": "1”,
    "brand": “Tata”,
    “name”: “Indica”,
    “color”: “Black”
  }

手机:

{
    "phone_id": "n0830bo”,
    "brand": “OnePlus”,
    “name”: “7 Pro”,
    “color”: “Red”
  },
  {
    "phone_id": "bh97b01”,
    "brand": “IPhone”,
    “name”: “11 Pro”,
    “color”: “Black”
  }

我会得到一个query_string,在这个collection中搜索,如果有匹配的结果,我应该得到所有相关的值。

示例:

如果 query_stringMartin,我应该从书籍 collection 中得到相应的结果,因为 Martin 只存在于那里:

 {
    "book_id": "a5g2nld”,
    "book_version": "1",
    "author": "Martin",
    "name": "Sample Book",
    “comments”: “In Progress”
  }

如果 query_stringBlack,我应该从 Cars 和 Phones collections 得到相应的结果,因为它们的值都是 Black:

{
    "car_id": "cak201n”,
    "car_model": "1”,
    "brand": “Tata”,
    “name”: “Indica”,
    “color”: “Black”
  },
{
    "phone_id": "bh97b01”,
    "brand": “IPhone”,
    “name”: “11 Pro”,
    “color”: “Black”
  }

这似乎很棘手,我不知道如何进行。任何帮助将不胜感激。

这里有几个选项。这些使用基本查询和 JavaScript 具有不同的复杂程度:


选项 #1:

查询每个集合要搜索的所有字段:

var booksFound = db.books.find( { $or [ { author: <querystring>} , { name: <querystring> } ]  } ).toArray()
var carsFound = db.cars.find( { $or [ { brand: <querystring> }, { name: <querystring> }, { color: <querystring> } ] } ).toArray()
var phonesFound = db.phones.find( { $or [ { brand: <querystring> }, { name: <querystring> }, { color: <querystring> } ] } ).toArray()

合并三个结果数组使用JavaScriptArrays#concat方法得到结果:

var resultArray = booksFound.concat(carsFound).concat(phonesFound);


索引和排序规则: 请注意,您必须在每个集合中的各个字段上创建索引以加快搜索速度。您还可以使用 collat​​ion: { collation: { locale: 'en', strength: 2 } } 向索引添加 case-insensitive 选项(用于不区分大小写的搜索)。请参阅 Case Insensitive Indexes.

上的注释



选项#2:

创建一个新的 keywords 字段,它将是一个 array 的值,来自您要搜索的字段。您可以将该字段命名为 "keywords" 或 "searchwords".

例如,cars 集合的 car_id: "nlp240n" 文档,您可以将关键字字段设置为 keywords: [ "Hyundai", "Verna", "Blue"]

您需要在此数组字段上创建索引以加快查询速度。数组上的索引称为多键索引。您还可以使用排序规则向索引添加 不区分大小写 选项。 有关排序规则的更多详细信息,请参阅选项 #1

注意:关键字字段和索引需要在三个集合上创建。

进行三个查询并将每个查询的结果作为数组获取:

var booksFound = db.books.find( { keywords: <querystring> } ).toArray();
var carsFound = db.cars.find( { keywords: <querystring> } ).toArray();
var phonesFound = db.phones.find( { keywords: <querystring> } ).toArray();

合并三个数组使用JavaScriptArrays#concat方法得到结果:

var resultArray = booksFound.concat(carsFound).concat(phonesFound);


如何创建关键字字段数据?

每次从集合中插入、更新或删除文档( 如果我们正在查询的任何字段是),关键字数组需要相应地更新。 插入时将值添加到数组,更新时更改数组中的值,删除时删除数组中的值

有关详细信息,请参阅此内容:Array Update Operators

对于你的情况,你可以这样做:

var searchValue = "Martin";
// FOR EACH COLLECTION IN MONGODB...
// HERE YOU COULD ITERAVE OVER AN ARRAY OF COLLECTIONS NAMES...
// var collections = ["Books", "Cars", "Phones"];
// collections.forEach(
db.getCollectionNames().forEach(
    function(collectionName) {
        // GETTING THE FIELD NAMES FOR THE COLLECTION...
        // FOR COLLECTIONS WITH MANY DOCUMENTS IT MAY BE MORE INTERESTING TO GET THE FIELD NAMES ELSEWHERE INSTEAD OF MONGODB...
        db.getCollection(collectionName).aggregate([
          {"$project":{"arrayOfKeyValue":{"$objectToArray":"$$ROOT"}}},
          {"$unwind":"$arrayOfKeyValue"},
          {"$group":{"_id":null,"allFields":{"$addToSet":"$arrayOfKeyValue.k"}}},
          {"$project":{"collectionName": collectionName, "fieldNames": "$allFields"}}
        ]).forEach(
            function(collectionWithFieldNames) {  
                // FOR EACH FIELD NAME OF THE COLLECTION...
                collectionWithFieldNames.fieldNames.forEach(
                    function(fieldName) {
                        var name = fieldName;
                        var value = searchValue;
                        var query = {};
                        query[name] = value;

                        // QUERY THE COLLECTION SEARCHING THE SEARCH VALUE ON THE FIELD IN THE COLLECTION...
                        db.getCollection(collectionName).find(query).forEach(
                            function(result) {
                                // PRINT THE RESULT IF EXISTS...
                                // HERE YOU CAN DO EVERYTHING WITH THE RESULT...
                                print(JSON.stringify(result));
                            }
                        );
                    }
                );
            }
        )
    }
);