PHP操作MongoDB如何实现仅匹配子文档键名的查询
PHP操作MongoDB匹配子文档键名查询方案
需求说明
需要实现等价于MySQL users like '"14:"' or invoice_id ="2"的查询效果,MongoDB中存储的文档结构如下:
{ "invoice_id": 0, "users": { "14": "2022-06-09 10:56:10", "212": "2022-06-09 04:05:35" } }, { "invoice_id": 2, "users": { "15": "2022-06-09 10:56:10", "246": "2022-06-09 04:05:35" } }
核心查询目标:筛选出users子文档中存在键名为14,或者invoice_id值为2的记录。
原有错误写法问题:
$data["users.0"] = new MongoDB\BSON\Regex("14"); $result = $collection->find($data, $option);
该写法仅会匹配子文档的字段值,无法针对子文档的键名做匹配,无法达到预期效果。
正确实现代码
根据查询场景分两种实现方式:
固定键名精确匹配(推荐)
如果是明确判断子文档是否存在指定键名(比如本需求中固定判断键14是否存在),直接使用$exists操作符即可,性能最优,可命中索引:$filter = [ '$or' => [ // 判断users子文档下键"14"是否存在 ['users.14' => ['$exists' => true]], // 匹配invoice_id=2的记录 ['invoice_id' => 2] ] ]; $result = $collection->find($filter, $option);模糊匹配子文档键名
如果需要用正则模糊匹配子文档的键名(比如匹配所有键名包含14的记录,而非固定精确键名),需要先用$objectToArray将子文档转为{k:键名, v:键值}格式的数组,再对数组元素的k字段(即原键名)做正则匹配:$filter = [ '$or' => [ [ '$expr' => [ '$gt' => [ [ '$size' => [ '$filter' => [ 'input' => ['$objectToArray' => '$users'], 'cond' => [ '$regexMatch' => [ 'input' => '$$this.k', 'regex' => '14' // 替换为实际需要的键名匹配正则 ] ] ] ] ], 0 ] ] ], ['invoice_id' => 2] ] ]; $result = $collection->find($filter, $option);
注意:非必要不使用模糊匹配键名的写法,该写法需要逐行做表达式计算,无法命中索引,数据量大时查询性能会非常差。固定键判断优先使用
$exists方案。
内容的提问来源于stack exchange,提问作者Shail
相关产品推荐
相关产品推荐

