MongoDB:在数组中插入和更新

时间:2014-11-12 04:58:52

标签: php mongodb

我有“_id”和“ProductLot”。如果ProductLot存在,如何在Lot数组中将数量“0”更新为“1”,如果不存在则添加新的Lot元素?

"_id" : ObjectId("5462e44c599e5c6c1300000a"),
"LocationName" : "Putaway", 
"Owner" : "", 
"Status" : "1", 
"Scrap" : "0", 
"Lot" : [{      
     "Qty" :"6",   
     "ProductLot" : ObjectId("5462dbd9599e5c200e000000"), 
     "Product" : ObjectId("543ca7be4cf59d400c000004"),       
     "Movement" :[ {"OriginId" : "266",Qty:2,Type:"DN"},
           {"OriginId" : "267" , Qty:1 , Type:"DN"},
           {"OriginId" : "2" , Qty:3 , Type:"IM"},

        ]
    },  
    {      
     "Qty" :"0",   
     "ProductLot" : ObjectId("5462dbd9599e5c200e000003"),  
     "Product" : ObjectId("543ca7be4cf59d400c000004"),    
     "Movement" :[ {"OriginId" : "266",Qty:2,Type:"DN"},
           {"OriginId" : "267" , Qty:1 , Type:"DN"},
           {"OriginId" : "2" , Qty:-3 , Type:"IM"},
        ]

    }] 
}

EG:我有“ProductLot”:ObjectId(“5462dbd9599e5c200e000000”)存在于数组中,因此它应该更新数量 0到1 ;但是,“ProductLot”:ObjectId(“5462dbd9599e5c200e00000a”)在数组中不可用,因此应该向数组附加一个新元素。

PHP代码,每次都不更新创建附加数组:

            $inventoryId = new \MongoId($_POST["inventoryid"]);
            $productLotId = new \MongoId($invlotid);
            $originId = $_POST['id'];
            //$lotcontent = [ /* whatever this looks like */ ];

            $lotcontent = array(
                     'Qty' => $invqty,
                     'ProductLot' => new \MongoId($invlotid),
                     'Product'=>$invproduct,
                     'Movement'=> array(
                            array(
                            'OriginId' => $_POST['id'],
                            'Qty' => $invqty,
                            'Type'=> 'DN',              
                            ),  )                   
                     );
            $invcolname = 'Inventory';
            $result = $mongo->$dbname->$invcolname->update(
            // Match an inventory without the specific ProductLot/OriginId element
            array(
                '_id' => $inventoryId,
                'Lot' =>    array(
                    '$not' =>   array(
                        '$elemMatch' => array(
                            'ProductLot' => $productLotId,
                            //'OriginId' => $originId,
                        ),
                    ),
                ),
            ),
            // Append a new element to the Lot array field
            array('$push' => array( 'Lot' => $lotcontent ))
            );

            $movementcontent =  array(
                            'OriginId' => $_POST['id'],
                            'Qty' => $invqty,
                            'Type'=> 'DN',              
                            );

            $result = $mongo->$dbname->$invcolname->update(
            // Match an inventory without the specific ProductLot/OriginId element
            array(
                '_id' => $inventoryId,
                'Lot' =>    array(
                    //'$not' =>     array(
                        '$elemMatch' => array(
                            'ProductLot' => $productLotId,                              
                            'Movement'=>array(
                                '$not' =>   array(
                                    '$elemMatch' => array(
                                        'OriginId' => $originId,
                                    )
                                )
                            )                               
                        ),
                   // ),
                ),
            ),
            // Append a new element to the Lot.Movement array field
            array('$push' => array( 'Lot.$.Movement' => $movementcontent ))
            );


            $result = $mongo->$dbname->$invcolname->update(
                // Match an inventory with a specific ProductLot/OriginId element
              array(
                    '_id' => $inventoryId,
                    'Lot' => array(
                        '$elemMatch' => array(
                            'ProductLot' => $productLotId,
                            //'OriginId' => $originId,
                            'Movement'=>array(
                                '$elemMatch' => array(
                                        'OriginId' => $originId,
                                    )
                            )
                        ),
                    ),
                ),
                // Update the "Qty" field of the first array element matched (if any)                  
               //array( '$set' => array( 'Lot.$.Qty' => 'Updated' )),
               array( '$set' => array( 'Lot.$.Movement.$.Qty' => $invqty )),
            array('upsert' => true));               

请有人帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

在这种情况下使用$addToSet会出现问题,因为以下lot元素会被视为不同:

{
    "Qty" :0,
    "ProductLot" : ObjectId("5462dbd9599e5c200e000003"),
    "Product" : ObjectId("543ca7be4cf59d400c000004"),
    "OriginId" : "266"
}

{
    "Qty" :5,
    "ProductLot" : ObjectId("5462dbd9599e5c200e000003"),
    "Product" : ObjectId("543ca7be4cf59d400c000004"),
    "OriginId" : "266"
}

第一个元素很可能是你要添加的(数量为0或1),第二个元素是相同的逻辑批量元素,只是增加了数量。如果后一个元素已经存在于数组中,我想你希望你的应用程序将数量从5增加到6而不是添加第一个元素,这实际上是重复的。

我们肯定需要两次更新,但我建议如下:

// Let's assume the following identifiers...
$inventoryId = new MongoId($_POST['inventoryid']);
$productLotId = new MongoId($invlotid);
$originId = new MongoId($_POST['id']);
$lotcontent = [ /* whatever this looks like */ ];

$result = $collection->update(
    // Match an inventory without the specific ProductLot/OriginId element
    [
        '_id' => $inventoryId,
        'Lot' => [
            '$not' => [
                '$elemMatch' => [
                    'ProductLot' => $productLotId,
                    'OriginId' => $originId,
                ],
            ],
        ],
    ],
    // Append a new element to the Lot array field
    [ '$push' => [ 'Lot' => $lotcontent ] ]
);

MongoCollection::update()将返回一个结果文档,其中包含n字段,表示受影响的文档数。由于我们没有使用multiple选项,并且_id最多也匹配一个文档,因此我们可以预期n为0或1.如果{{1} }为0,我们要么找不到包含n的广告资源文档,要么我们找到了一个但是已经有_id元素的产品和来源标识符(即我们的Lot标准匹配的东西,使我们的否定无效)。如果$elemMatch为1,则表示我们找到了库存文档,但它不包含匹配的n元素,并且我们附加了它(即我们的工作已完成)。

假设Lot为0,我们应该发出另一个更新并尝试增加数量:

n

在这里,我使用$ positional update operator来访问标准中匹配的特定数组元素。这允许我们制作$result = $collection->update( // Match an inventory with a specific ProductLot/OriginId element [ '_id' => $inventoryId, 'Lot' => [ '$elemMatch' => [ 'ProductLot' => $productLotId, 'OriginId' => $originId, ], ], ], // Update the "Qty" field of the first array element matched (if any) [ '$inc' => [ 'Lot.$.Qty' => 1 ] ] ); 而不用担心匹配元素的索引。

同样,我们可以在这里查看$inc。如果它仍为0,那么我们可以假设没有文档与我们的$result['n']匹配(一个完全独立的错误)。但如果此时_id为1,我们成功增加了数量,我们的工作就完成了。