0

根据PHP 文档,该existsInDatabase()方法旨在确定数据库中是否存在 Collection 的实例(作为 SchemaObject aka 表)。但是只有当它的表模式完全符合使用该方法创建时的模式时,它才会认为 Collection 存在Schema::createCollection(),例如。恰好 2 列称为doc_id

这是由于 PHP 模块过于严格导致的错误吗?

这是一个演示(取决于mysql_xdevapi PHP 模块 ...

首先,使用 MySQL 在您的数据库中创建一个名为“people”的集合(取自JavaScript/Python 示例中 MySQL 的 world_x.sql 脚本):

CREATE TABLE `countryinfo` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    `_json_schema` json GENERATED ALWAYS AS (_utf8mb4'{"type":"object"}') VIRTUAL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

其次,创建一个名为“people”的集合,与上面非常相似,但_json_schema省略了列:

CREATE TABLE `people` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

第三,使用 PHP 的createCollection()方法创建一个名为“animals”的集合:

$dbSession = mysql_xdevapi\getSession("mysqlx://test:test@localhost");

$schema = $dbSession->getSchema("world_x");    

$collection = $schema->createCollection('animals');

现在,使用 PHP 的existsInDatabase()方法检查 3 个集合:

$dbSession = mysql_xdevapi\getSession("mysqlx://test:test@localhost");

$schema = $dbSession->getSchema("world_x");

if ($schema->getCollection('countryinfo')->existsInDatabase()) {
    print "countryinfo collection exist! ";
}

if ($schema->getCollection('people')->existsInDatabase()) {
    print "People collection exist! ";
}

if ($schema->getCollection('animals')->existsInDatabase()) {
    print "Animals collection exist! ";
}

根据 MySQL 文档,所有这 3 个都是有效的集合,但上面的 PHP 代码仅将“人”和“动物”识别为存在。

作为进一步的实验,使用 MySQL 将任何随机命名的列添加到名为“animals”的集合(通过 PHP 创建)并重新执行脚本以查看它现在如何认为它不存在。

ALTER TABLE animals ADD COLUMN test tinyint;

现在,如果您使用$schema->getCollections()$schema->getTables()您将看到它animals被归类为表而不是集合。删除该列,它会再次跳回。在引擎盖下,这是模块决定 Collection 是否“存在”的方式。

我怀疑 PHP 模块可能过于严格。这是一个问题,因为它将您的数据库模式与特定语言紧密耦合。例如,如果我想构建一个 PHP 脚本来与最初通过 JavaScript 填充的现有 MySQL 文档存储进行交互,它可能会出现错误,因为可能_json_schema在某些/所有集合中存在额外的列(或其他一些列) .

我认为有其他列是合法的doc_id因为我没有找到相反的规范。我可以想象一个非常真实的用例,created_at在 Collection 上有一个 datetime 列。

或者,我是否真的发现了不是 PHP 模块而是 MySQLs 文档的问题?该_json_schema列是否是早期版本的遗留问题,现在应该删除?集合表的定义现在是否已在所有语言中标准化,并且它们必须严格按照指定的那两列来定义?

MySQL 含糊不清,但 PHP 很严格,这一切都有些蓬松。

任何帮助表示赞赏。如果一致认为存在错误,我将向维护人员报告错误。

4

1 回答 1

1

------------------------------- {编辑 4 月 21 日} -------------- -----------------

看起来 xplugin/server 的行为既没有任何错误,也没有变化。不允许向集合添加额外的列。'countryinfo' 集合中的 _json_schema 列不被视为额外的东西 - 它用于称为“模式验证”的新功能,并且是可选的。所以它可能出现在集合的表中,也可能不出现。因此,给定的表仍然被视为集合,无论它是否包含“_json_schema”。虽然,将其名称从 '_json_schema' 更改为例如 'json_schema' (即仅删除前导下划线)就足够了,它将被视为额外列,因此给定的表将不再报告为集合(existsInDatabase() 返回错误的)。

引用样本:

https://dev.mysql.com/doc/refman/8.0/en/mysql-shell-tutorial-javascript-download.html

适用于 8.0.19,但看起来该版本的服务器已经为“模式验证”做好了准备,而 mysql_xdevapi 将从 v8.0.21 开始正式支持该功能。

在这样的调用之后提到的新版本 .21 中:

$coll = $schema->createCollection("animals");

“动物”表中的列将如下所示

mysql> show columns from animals;
+--------------+---------------+------+-----+---------+-------------------+
| Field        | Type          | Null | Key | Default | Extra             |
+--------------+---------------+------+-----+---------+-------------------+
| doc          | json          | YES  |     | NULL    |                   |
| _id          | varbinary(32) | NO   | PRI | NULL    | STORED GENERATED  |
| _json_schema | json          | YES  |     | NULL    | VIRTUAL GENERATED |
+--------------+---------------+------+-----+---------+-------------------+
3 rows in set (0.00 sec)

并将报告为集合。

------------------------------- {4 月 21 日编辑结束} ------------ ------------------

我们检查了 con/php 的行为,看起来它的性能与 con/nodejs 相似,即

  1. 'countryinfo' 被报告为集合
  2. 添加/删除列也会导致 con/nodejs 或 shell 中报告的“动物”类型发生变化(集合与表)。

请运行以下脚本,让我们知道您的环境中的输出是什么。

// please align below variables according to your environment
$connection_uri = "mysqlx://test:test@localhost";
$db = "testx";

$session = mysql_xdevapi\getSession($connection_uri);
$session->sql("create database $db")->execute();
$schema = $session->getSchema($db);

$session->sql("USE $db")->execute();

$countryinfo_table_stmt="CREATE TABLE `countryinfo` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    `_json_schema` json GENERATED ALWAYS AS (_utf8mb4'{\"type\":\"object\"}') VIRTUAL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";

echo "$countryinfo_table_stmt\n";
$session->sql($countryinfo_table_stmt)->execute();

$people_table_stmt="CREATE TABLE `people` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";

echo "$people_table_stmt\n";
$session->sql($people_table_stmt)->execute();

if ($schema->getCollection('countryinfo')->existsInDatabase()) {
    print "countryinfo collection exists!\n";
} else {
    print "countryinfo collection DOES NOT exist!\n";
}

if ($schema->getCollection('people')->existsInDatabase()) {
    print "People collection exists!\n";
} else {
    print "People collection DOES NOT exist!\n";
}

$coll = $schema->createCollection("animals");

if ($schema->getCollection('animals')->existsInDatabase()) {
    print "Animals collection exists!\n";
} else {
    print "Animals collection DOES NOT exist!\n";
}

$session->sql("ALTER TABLE $db.animals ADD COLUMN test tinyint")->execute();

if ($schema->getCollection('animals')->existsInDatabase()) {
    print "Animals collection exists!\n";
} else {
    print "Animals collection DOES NOT exist!\n";
}

$session->sql("ALTER TABLE $db.animals DROP COLUMN test")->execute();

if ($schema->getCollection('animals')->existsInDatabase()) {
    print "Animals collection exists!\n";
} else {
    print "Animals collection DOES NOT exist!\n";
}

print "done!\n";

在我们的环境中,输出如下所示:

CREATE TABLE `countryinfo` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    `_json_schema` json GENERATED ALWAYS AS (_utf8mb4'{"type":"object"}') VIRTUAL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
CREATE TABLE `people` (
    `doc` json DEFAULT NULL,
    `_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
    PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
countryinfo collection exists!
People collection exists!
Animals collection exists!
Animals collection DOES NOT exist!
Animals collection exists!
done!

此外,您使用的服务器/连接器版本是多少?

于 2020-04-10T05:29:43.843 回答