【问题标题】:Search scope in MongoDB, want subelement, not entire document在 MongoDB 中搜索范围,需要子元素,而不是整个文档
【发布时间】:2017-07-06 13:13:14
【问题描述】:

我有结构相当复杂的 MongoDB 文档:

顶级组织(一个元素)

许多属性,其中有趣的是创始人经理

founders - 是一个创始人列表,每个创始人都有姓氏、名字、父名(和其他属性)

ma​​nagers 相同 - 包含姓氏、名字、父名(和其他属性)的元素列表

我想在一个查询中按姓氏 + 名字 + 父名组合进行搜索。 查询应该支持多个姓氏、名字、父名(在 $in 的帮助下)(用于一个人的不同名字,即 jon、john、johny)

我当前的代码返回 ORGANISATION 中姓氏 + 名字 + 父名组合的组织,但我需要 PERSON 中的姓氏 + 名字 + 父名组合。可能吗?即使是正确的方向,而不是代码,也会感激不尽。据我了解, $elemMatch 不会帮助我,否则查询会很麻烦?也许确实存在更清洁的选择?

我已经尝试过改变

List<BasicDBObject> args 

BasicDBObject name

并用追加填充它。没有任何改变。

我的代码:

List<BasicDBObject> args = new ArrayList<>();
args.add(new BasicDBObject("founders.typeperson.person.lastname", new BasicDBObject("$in", request.getLastnames())));
args.add(new BasicDBObject("founders.typeperson.person.firstname", new BasicDBObject("$in", request.getFirstnames())));
args.add(new BasicDBObject("founders.typeperson.person.patronym", new BasicDBObject("$in", request.getPatronyms())));
argsListUL.add(new BasicDBObject("$and", args));

result = collection.find(new BasicDBObject("$or", argsListUL)).into(new ArrayList<Document>());

实际上,最终的 argsListUL 中有更多的 DBObject,但为了简单起见,我删除了该代码。

更新 尝试使用 $elemMatch 在 shell 中构造最简单的查询。奇怪,但它不起作用:

db.collection.find( { "founders.typeperson.person": { $elemMatch: { "lastname": "bla" , "firstname": "bla","patronym" : "bla"  } } } ).pretty()

得到 0 个结果。虽然 DB 中存在姓氏 + 名字 + 父名的组合。

另一个注意事项:数据库大小为 500GB,所以我认为投影中的 $elemMatch 会太慢。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    也许您应该尝试共享您的数据库方案。您的问题不清楚您的数据库方案。

    尽管据我了解,您的数据结构如下。虽然如果结构或要求有任何不同,我会更新答案。

    {
      "_id": ObjectId(''),
      "organization": "x",
      founders: [
        {
          lastname: 'a'
          firstname: 'a',
          patronym: 'a'
        },
        {
          lastname: 'b'
          firstname: 'b',
          patronym: 'b'
        }
      ],
      managers: [
        {
          {
            lastname: 'c'
            firstname: 'c',
            patronym: 'c'
          },
          {
            lastname: 'd'
            firstname: 'd',
            patronym: 'd'
          }
        }
      ]
    
    }
    

    我可以建议您查看聚合管道。

    您可以用来获取子文档的查询是:-

    db.collection.aggregate([{
      $match: {
        'organization': '<name>'
      }
    }, {
      $unwind: '$managers'
    }, {
      $unwind: '$founders'
    }, {
      $match: {
    
        $or: [{
          $or: [{
            "managers.lastname": {
              $regex: 'searchString',
              $options: 'i'
            }
          }, {
            "managers.firstname": {
              $regex: 'searchString',
              $options: 'i'
            }
          }, {
            "managers.patronym": {
              $regex: 'searchString',
              $options: 'i'
            }
          }]
        }, {
          $or: [{
            "founders.lastname": {
              $regex: 'searchString',
              $options: 'i'
            }
          }, {
            "founders.firstname": {
              $regex: 'searchString',
              $options: 'i'
            }
          }, {
            "founders.patronym": {
              $regex: 'searchString',
              $options: 'i'
            }
          }]
        }]
      }
    }, {
      $group: {
        "_id": {
          "_id": "$_id",
          "organization": "$organization",
        },
        "founders": {
          "$push": '$founders'
        }, 
        "managers": {
          "$push": '$managers'
        }
      }
    }, {
      $project: {
        "_id": 0,
        "founders": 1,
        "managers" 1
      }
    }])
    

    如果创建者和管理者子文档中存储的数据不大,$regex 查询不会导致任何性能瓶颈。

    【讨论】:

    • 感谢您的回答。您通常对结构是正确的,但我的搜索不是组织名称,而是全名组合。数据集相当庞大,500GB:6000 万个组织(每个组织有 1 到 10000 名创始人)。现在我在想 - 最快的方法是将全名合并到一个字段。这样它会很快工作。
    • 好吧,你想要的是一次搜索这 6000 万个组织的创始人和经理。您是否对数据库进行了分片?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 2018-02-09
    • 1970-01-01
    • 2015-03-26
    • 2017-12-31
    相关资源
    最近更新 更多