【问题标题】:MongoDB filter by reference's field (ORM)MongoDB 按引用字段过滤 (ORM)
【发布时间】:2015-01-29 23:05:05
【问题描述】:

假设我有文档city 和文档country

city'由country: ObjectId("xxxx")引用country

如何按国家/地区字段查找城市,例如。 db.Cities.find({"country.code":"US"}

有可能吗?我认为不会,但是否可以将 MongoDB ORM 用于 PHP?

我试过了

$qb = $this->database->createQueryBuilder(self::NAMESPACE_CITY);
$qb->field('country.code')->equals("US")`

我的City 实体包含

/** @ODM\ReferenceOne(targetDocument="\Doctrine\Documents\Country", simple=true) */
protected $country;

文档示例:

<?php

namespace Doctrine\Documents;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Application\Doctrine\Documents\Document;

/** @ODM\Document(collection="Cities") */
class City extends Document {

    /** @ODM\Id */
    protected $_id;

    /** @ODM\ReferenceOne(targetDocument="\Doctrine\Documents\Country", simple=true) */
    protected $country;

}

【问题讨论】:

  • 这将是一个有点自以为是的评论:文档存储数据库对于任何类型的具有关系的业务逻辑都是很糟糕的。为了您对这个主题感兴趣,这里有一个good article(标题很糟糕)。
  • 呵呵,是的,我知道他们对这个很糟糕......我希望它可以通过某种方式解决,至少通过 ORM......
  • 你能提供一个样本文件吗?

标签: php mongodb orm


【解决方案1】:

在单个查询中按国家/地区代码查询城市文档需要加入两个集合,这是不受支持的。您可以通过首先找到具有给定代码的国家/地区来将其分解为两个查询,我假设这是一个唯一的字符串。该查询将产生国家的 ObjectId,然后您可以使用它来查询城市集合:

{ "country": ObjectId(...) }

如果出于某种原因,您想通过国家/地区的某些非唯一值(例如,大陆、名称上的子字符串匹配)来查找城市,这仍然可以在两个查询中完成。第一个将再次为符合条件的任何国家/地区查找 ObjectId。然后,第二个查询将使用带有 ObjectId 数组的 $in 运算符:

{ "country": { "$in": [ ObjectId(...), ObjectId(...), ... ]}}

如果您使用Doctrine MongoDB ODM,查询生成器通过Expr.php 中的references()includesReferenceTo() 方法支持此功能(也通过Builder.php 公开)。 references()includesReferenceTo() 可分别用于匹配存在于 ReferenceOne 或 ReferenceMany 关系中的单个文档引用。它们还可以正确处理简单(即仅 ObjectId)和复杂(即DBRef)引用。

也就是说,ODM 查询构建器没有具有匹配多个引用的方法(请注意,上述两种方法都采用单个文档参数)。正如我在第二段中提到的,由于您使用的是简单的引用,因此使用in() 应该很容易做到这一点;但是,如果我们使用 DBRefs,查询会更加复杂(我们需要混合使用$elemMatch$in,如this answer 中所述)。我在 ODM 项目上打开了issue #1024 来跟踪这个功能请求。

【讨论】:

    【解决方案2】:

    您必须为 @MongoDB\ReferenceOne 使用查询构建器的 references() 方法,例如 https://doctrine-mongodb-odm.readthedocs.org/en/latest/reference/query-builder-api.html

    $country = $dm->getRepository('Country')->findOneByCode('US');
    
    $queryBuilder = $dm->getRepository('City')->createQueryBuilder()
                       ->field('country')->references($country);
    
    $citiesByCountry = $queryBuilder->getQuery()->execute();
    


    PS:使用 includesReferenceTo() @MongoDB\ReferenceMany

    【讨论】:

      猜你喜欢
      • 2021-10-23
      • 1970-01-01
      • 2015-07-23
      • 1970-01-01
      • 2017-07-02
      • 2021-10-20
      • 2020-10-23
      • 2022-11-19
      • 1970-01-01
      相关资源
      最近更新 更多