MongoDB Doctrine:$ in需要一个数组 - 多对多关系

时间:2014-09-02 19:26:57

标签: mongodb doctrine fatal-error doctrine-odm odm

我有一些包含产品的类别,而您可以将产品添加到类别中。这是一个多对多的关系,而产品不知道它们与一个类别的关系(因为它只保存在一个类别中)。我将首先发布我的设置,然后发出导致问题的查询。

/** @ODM\Document */
class Category
{
    /** @ODM\Id */
    private $id;

    /** @ODM\String */
    private $name;

    /** @ODM\ReferenceMany(targetDocument="Product", inversedBy="category") */
    private $products;

    public function setProducts($products)
    {
        $this->products = $products;
    }
}

/** @ODM\Document */
class Product
{
    /** @ODM\Id */
    private $id;

    /** @ODM\String */
    private $name;

    /** @ODM\Float */
    private $price;

    /** @ODM\ReferenceMany(targetDocument="Category", mappedBy="products") */
    private $category;
}

为了获得一些数据,我这样创建:

$p1 = new Documents\Product();
$p1->setName('p1');
$p1->setPrice(1.99);

$p2 = new Documents\Product();
$p2->setName('p2');
$p2->setPrice(3.99);

$c1 = new Documents\Category();
$c1->setName('category1');
$c1->setProducts(array($p1, $p2));

$c2 = new Documents\Category();
$c2->setName('category2');
$c2->setProducts(array($p1, $p2));

$dm->persist($p1);
$dm->persist($p2);
$dm->persist($c1);
$dm->persist($c2);
$dm->flush();

展望MongoDB,我现在有以下数据:

db.Category.find()
{ "_id" : ObjectId("53e3d8d3e2afec2303d63afa"), "name" : "category1", "products" : [ DBRef("Product", ObjectId("53e3d8d3e2afec2303d63af8")), DBRef("Product", ObjectId("53e3d8d3e2afec2303d63af9")) ] }
{ "_id" : ObjectId("53e3d8d3e2afec2303d63afb"), "name" : "category2", "products" : [ DBRef("Product", ObjectId("53e3d8d3e2afec2303d63af8")), DBRef("Product", ObjectId("53e3d8d3e2afec2303d63af9")) ] }

db.Product.find()
{ "_id" : ObjectId("53e3d8d3e2afec2303d63af8"), "name" : "p1", "price" : 1.99 }
{ "_id" : ObjectId("53e3d8d3e2afec2303d63af9"), "name" : "p2", "price" : 3.99 }

我现在想查询这些数据:按ID获取产品并获取其所有类别,它属于:

$product = $dm->find('Documents\Product', '53e3d8d3e2afec2303d63af8');
var_export($product->getName());
$category = $product->getCategory();
var_export(sizeof($category));
foreach($category as $c){
    var_export($c->getName());
}

// Outputs: 'p1' 2 'category1' 'category2'

但是,如果我想以相反的方式查询数据:获取类别并获取其所有产品,该类别包含:

$category = $dm->find('Documents\Category', '53e3d8d3e2afec2303d63afa');
var_export($category->getName());
$products = $category->getProducts();
var_export(sizeof($products));
foreach($products as $p){
    var_export($p->getName());
}

// Outputs: 'category1' 2

没有显示任何产品,我收到致命错误:

Fatal error: Uncaught exception 'MongoCursorException' with message 'localhost:27017: Can't canonicalize query: BadValue $in needs an array' in /private/var/www/mongo/vendor/doctrine/mongodb/lib/Doctrine/MongoDB/Cursor.php on line 288

如果我查看MongoDB日志,查询如下:

assertion 17287 Can't canonicalize query: BadValue $in needs an array ns:shop.Product query:{ $query: { _id: { $in: { 53e3d8d3e2afec2303d63af8: ObjectId('53e3d8d3e2afec2303d63af8'), 53e3d8d3e2afec2303d63af9: ObjectId('53e3d8d3e2afec2303d63af9') } } }, $orderby: [] }

我的意思是,问题似乎很清楚:$in需要一个数组,但是没有给出JSON数组。但我不知道如何修复它。我究竟做错了什么?如果你不能回答这个特殊的问题,你能为我提供一个MongoDB与Doctrine的工作实例吗?你有这样的多对多关系,可以双方查询数据吗?

更新:我可能应该提到,我使用的是哪个版本的学说。我用过这个设置:

{
    "require":{
        "doctrine/common":"2.3.*",
        "doctrine/dbal":"2.3.*",
        "doctrine/orm":"*",
        "doctrine/mongodb-odm": "1.0.0-BETA9"
    }
}

然后我考虑更新到可用的最新版本并使用此设置:

{
     "require":{
        "doctrine/common":"2.4.*",
        "doctrine/dbal":"2.3.*",
        "doctrine/orm":"*",
        "doctrine/mongodb-odm": "dev-master"
    }
}

瞧瞧:一切都很好......天啊。但是对此的任何解释仍然是受欢迎的,我想知道这里发生了什么。非常感谢。

1 个答案:

答案 0 :(得分:2)

您遇到的错误已在PR #743中修复,该问题已包含在1.0.0-BETA10中。这是与MongoDB 2.6兼容所需的几个修复之一(请参阅issue #741),因为服务器在验证查询条件方面变得更加严格。

2.4之前的服务器版本接受了$in的对象,并且只是忽略了这些键。如果你看一下BSON specification,你会发现除了类型代码之外,数组和对象的结构非常相似。每个都是键/值对的序列,并且数组有效负载看起来非常像具有顺序数字字符串作为其键的对象。这应该可以解释为什么旧服务器版本很容易接受这两种类型。