如何在 mongo db 中进行条件更新?
How to do conditional update in mongo db?
我正在尝试更新文档的子文档,如下面的代码行
$bulkbatch = new MongoDB\Driver\BulkWrite(['ordered' => true]);
$subDocumentStatus = array(
"Status" => array(
"CurrentStatus" => $this->EmployeeStatus,
"StatusDate" => new MongoDB\BSON\UTCDateTime(strtotime($this->EmployeeStatusDate)*1000),
"IsActive" => $IsActive
)
);
$bulkbatch->update(
array(
'_id' => new MongoDB\BSON\ObjectID($this->id)
),
array(
'$addToSet' => $subDocumentStatus
),
[
'multi' => true,
'upsert' => false
]
);
$this->manager->executeBulkWrite($this->collection, $bulkbatch);
我有这样的文件
{
"EmployeeNumber": "123456",
"Instructor": NumberInt(1),
"Department": ObjectId("5a8173e6d2ccda13240015a4"),
"FirstName": "Faiza",
"MiddleName": "Yousuf",
"Status": [
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2018-02-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
}
],
...
...
}
如果 $this->EmployeeStatus 包含 "Joined" 并且 $this->EmployeeStatusDate 包含一些不同的值,例如上面的文档,它包含“2019-05-28T23:00:00.0Z”(不同于之前的值) 那么它应该被更新。
以上代码是插入另一个子文档
值如
"Status": [
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2018-02-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
},
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2019-05-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
}
],
...
我希望在加入的情况下更新现有的子文档。
请帮忙!!!
有两个 Mongo 调用的解决方案;首先尝试更新现有的 sub-document;如果没有 sub-document 被修改,则在主文档中插入一个。
这里有一个unit-test证明解决方案有效(主要功能是updateOrInsert
):
require_once __DIR__ . '/MongoTestHelper.php';
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\UTCDateTime;
use tests\Dudulina\MongoTestHelper;
class TmpTest extends \PHPUnit_Framework_TestCase
{
/** @var \MongoDB\Collection */
private $collection;
/** @var ObjectID */
private $_id;
public function test_subdocumentExists()
{
$statusDate = new UTCDateTime(strtotime("2018-02-28T23:00:00.0Z"));
$employeeStatus = "Joined";
/**
* Test data
*/
$this->collection->insertOne([
"_id" => $this->_id,
"EmployeeNumber" => "123456",
"Instructor" => 1,
"Department" => new ObjectID("5a8173e6d2ccda13240015a4"),
"FirstName" => "Faiza",
"MiddleName" => "Yousuf",
"Status" => [
[
"CurrentStatus" => $employeeStatus,
"StatusDate" => $statusDate,
"IsActive" => 1,
],
],
]);
/**
* the real test
*/
$this->updateOrInsert($employeeStatus, $statusDate, 0);
/**
* we verify the execution
*/
$document = $this->collection->findOne([
"_id" => $this->_id,
]);
$this->assertCount(1, $document['Status']);
$this->assertSame(0, $document['Status'][0]['IsActive']);
}
public function test_subdocumentDoesNotExists()
{
$statusDate = new UTCDateTime(strtotime("2018-02-28T23:00:00.0Z"));
$employeeStatus = "Joined";
/**
* we insert some test data
*/
$this->collection->insertOne([
"_id" => $this->_id,
"EmployeeNumber" => "123456",
"Instructor" => 1,
"Department" => new ObjectID("5a8173e6d2ccda13240015a4"),
"FirstName" => "Faiza",
"MiddleName" => "Yousuf",
"Status" => [
[
"CurrentStatus" => 'SomeOtherStatus',
"StatusDate" => new UTCDateTime(strtotime("2010-02-28T23:00:00.0Z")),
"IsActive" => 1,
],
],
]);
/**
* the real test
*/
$this->updateOrInsert($employeeStatus, $statusDate, 0);
/**
* we verify the execution
*/
$document = $this->collection->findOne([
"_id" => $this->_id,
]);
/**
* now there are 2 subdocuments inserted
*/
$this->assertCount(2, $document['Status']);
/**
* we verify the second document
*/
$secondSubDocument = $document['Status'][1];
$this->assertSame(0, $secondSubDocument['IsActive']);
$this->assertSame('Joined', $secondSubDocument['CurrentStatus']);
$this->assertTrue($statusDate->toDateTime()->getTimestamp() === $secondSubDocument['StatusDate']->toDateTime()->getTimestamp());
}
/**
* The function that you should do
*/
private function updateOrInsert($employeeStatus, $statusDate, $isActive)
{
$updateResult = $this->collection->updateOne([
"_id" => $this->_id,
"Status.CurrentStatus" => $employeeStatus,
"StatusDate" => ['$ne' => $statusDate],
], [
'$set' => [
'Status.$.StatusDate' => $statusDate,
'Status.$.IsActive' => $isActive,
],
], [
'upsert' => false,
]);
if ($updateResult->getModifiedCount() === 0) {
$this->collection->updateOne([
"_id" => $this->_id,
], [
'$addToSet' => [
'Status' => [
"CurrentStatus" => $employeeStatus,
"StatusDate" => $statusDate,
"IsActive" => $isActive,
],
],
], [
'upsert' => false,
]);
}
}
protected function setUp()
{
$this->collection = (new MongoTestHelper())->selectCollection('eventStore');
$this->collection->deleteMany([]);
$this->_id = new ObjectID('47ecbc36e8fb4b50662adcf9');
}
}
我正在尝试更新文档的子文档,如下面的代码行
$bulkbatch = new MongoDB\Driver\BulkWrite(['ordered' => true]);
$subDocumentStatus = array(
"Status" => array(
"CurrentStatus" => $this->EmployeeStatus,
"StatusDate" => new MongoDB\BSON\UTCDateTime(strtotime($this->EmployeeStatusDate)*1000),
"IsActive" => $IsActive
)
);
$bulkbatch->update(
array(
'_id' => new MongoDB\BSON\ObjectID($this->id)
),
array(
'$addToSet' => $subDocumentStatus
),
[
'multi' => true,
'upsert' => false
]
);
$this->manager->executeBulkWrite($this->collection, $bulkbatch);
我有这样的文件
{
"EmployeeNumber": "123456",
"Instructor": NumberInt(1),
"Department": ObjectId("5a8173e6d2ccda13240015a4"),
"FirstName": "Faiza",
"MiddleName": "Yousuf",
"Status": [
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2018-02-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
}
],
...
...
}
如果 $this->EmployeeStatus 包含 "Joined" 并且 $this->EmployeeStatusDate 包含一些不同的值,例如上面的文档,它包含“2019-05-28T23:00:00.0Z”(不同于之前的值) 那么它应该被更新。
以上代码是插入另一个子文档 值如
"Status": [
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2018-02-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
},
{
"CurrentStatus": "Joined",
"StatusDate": ISODate("2019-05-28T23:00:00.0Z"),
"IsActive": NumberInt(1)
}
],
...
我希望在加入的情况下更新现有的子文档。
请帮忙!!!
有两个 Mongo 调用的解决方案;首先尝试更新现有的 sub-document;如果没有 sub-document 被修改,则在主文档中插入一个。
这里有一个unit-test证明解决方案有效(主要功能是updateOrInsert
):
require_once __DIR__ . '/MongoTestHelper.php';
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\UTCDateTime;
use tests\Dudulina\MongoTestHelper;
class TmpTest extends \PHPUnit_Framework_TestCase
{
/** @var \MongoDB\Collection */
private $collection;
/** @var ObjectID */
private $_id;
public function test_subdocumentExists()
{
$statusDate = new UTCDateTime(strtotime("2018-02-28T23:00:00.0Z"));
$employeeStatus = "Joined";
/**
* Test data
*/
$this->collection->insertOne([
"_id" => $this->_id,
"EmployeeNumber" => "123456",
"Instructor" => 1,
"Department" => new ObjectID("5a8173e6d2ccda13240015a4"),
"FirstName" => "Faiza",
"MiddleName" => "Yousuf",
"Status" => [
[
"CurrentStatus" => $employeeStatus,
"StatusDate" => $statusDate,
"IsActive" => 1,
],
],
]);
/**
* the real test
*/
$this->updateOrInsert($employeeStatus, $statusDate, 0);
/**
* we verify the execution
*/
$document = $this->collection->findOne([
"_id" => $this->_id,
]);
$this->assertCount(1, $document['Status']);
$this->assertSame(0, $document['Status'][0]['IsActive']);
}
public function test_subdocumentDoesNotExists()
{
$statusDate = new UTCDateTime(strtotime("2018-02-28T23:00:00.0Z"));
$employeeStatus = "Joined";
/**
* we insert some test data
*/
$this->collection->insertOne([
"_id" => $this->_id,
"EmployeeNumber" => "123456",
"Instructor" => 1,
"Department" => new ObjectID("5a8173e6d2ccda13240015a4"),
"FirstName" => "Faiza",
"MiddleName" => "Yousuf",
"Status" => [
[
"CurrentStatus" => 'SomeOtherStatus',
"StatusDate" => new UTCDateTime(strtotime("2010-02-28T23:00:00.0Z")),
"IsActive" => 1,
],
],
]);
/**
* the real test
*/
$this->updateOrInsert($employeeStatus, $statusDate, 0);
/**
* we verify the execution
*/
$document = $this->collection->findOne([
"_id" => $this->_id,
]);
/**
* now there are 2 subdocuments inserted
*/
$this->assertCount(2, $document['Status']);
/**
* we verify the second document
*/
$secondSubDocument = $document['Status'][1];
$this->assertSame(0, $secondSubDocument['IsActive']);
$this->assertSame('Joined', $secondSubDocument['CurrentStatus']);
$this->assertTrue($statusDate->toDateTime()->getTimestamp() === $secondSubDocument['StatusDate']->toDateTime()->getTimestamp());
}
/**
* The function that you should do
*/
private function updateOrInsert($employeeStatus, $statusDate, $isActive)
{
$updateResult = $this->collection->updateOne([
"_id" => $this->_id,
"Status.CurrentStatus" => $employeeStatus,
"StatusDate" => ['$ne' => $statusDate],
], [
'$set' => [
'Status.$.StatusDate' => $statusDate,
'Status.$.IsActive' => $isActive,
],
], [
'upsert' => false,
]);
if ($updateResult->getModifiedCount() === 0) {
$this->collection->updateOne([
"_id" => $this->_id,
], [
'$addToSet' => [
'Status' => [
"CurrentStatus" => $employeeStatus,
"StatusDate" => $statusDate,
"IsActive" => $isActive,
],
],
], [
'upsert' => false,
]);
}
}
protected function setUp()
{
$this->collection = (new MongoTestHelper())->selectCollection('eventStore');
$this->collection->deleteMany([]);
$this->_id = new ObjectID('47ecbc36e8fb4b50662adcf9');
}
}