如何使用Predis在树结构中写入数据?

huangapple go评论87阅读模式
英文:

How with predis to write data in tree structure?

问题

我明白你需要的只是代码部分的翻译。以下是翻译好的代码部分:

更新的块1:
我将示例代码复制到我的应用程序中:

  1. $data = [
  2. 'name' => 'John Doe',
  3. 'email' => 'johndoe@example.com',
  4. 'address' => [
  5. 'street' => '123 Main St',
  6. 'city' => 'Anytown',
  7. 'state' => 'CA',
  8. 'zip' => '12345'
  9. ]
  10. ];
  11. Redis::hmset('user:1', $data); // 错误指向了这一行173

但我收到了错误:

  1. php artisan job:dispatchNow ArticlesCachingJob
  2. ErrorException
  3. Array to string conversion
  4. vendor/predis/predis/src/Connection/StreamConnection.php 的第365
  1. 我在代码中进行了调试,并在vendor/predis/predis/src/Connection/StreamConnection.php文件中添加了2行日志记录:
  1. public function writeRequest(CommandInterface $command) // 第352行
  2. {
  3. $commandID = $command->getId();
  4. $arguments = $command->getArguments();
  5. $cmdlen = strlen($commandID);
  6. $reqlen = count($arguments) + 1;
  7. $buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";
  8. foreach ($arguments as $argument) {
  9. \Log::info(' $argument::');
  10. \Log::info($argument);
  11. $arglen = strlen(strval($argument));
  12. $buffer .= "${$arglen}\r\n{$argument}\r\n";
  13. }
  14. $this->write($buffer);
  15. }
  1. 我尝试用serialize方法包装'address'数组 - 它正常工作,这是我在phpRedisAdmin中看到的:https://prnt.sc/BMnRev9HDwZz

  2. 是否必须对所有子数组使用serialize方法?

  3. 我有Redis服务器 v=5.0.7 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=66bd62

在Kubuntu 20.04下

更新的块2:

我尝试了两种方法:

  1. $data = [
  2. 'name' => 'John Doe',
  3. 'email' => 'johndoe@example.com',
  4. 'address' => (object)[
  5. 'street' => '123 Main St',
  6. 'city' => 'Anytown',
  7. 'state' => 'CA',
  8. 'zip' => '12345'
  9. ]
  10. ];
  11. Redis::hset('user:1', $data);

  1. $data = [
  2. 'name' => 'John Doe',
  3. 'email' => 'johndoe@example.com',
  4. 'address' => [
  5. 'street' => '123 Main St',
  6. 'city' => 'Anytown',
  7. 'state' => 'CA',
  8. 'zip' => '12345'
  9. ]
  10. ];
  11. Redis::hset('user:1', (object)$data);

两者都导致错误:

  1. Array to string conversion
  2. vendor/predis/predis/src/Connection/StreamConnection.php 的第365

看起来任何值都必须是字符串(或序列化的字符串)?

谢谢!

英文:

Reading some manuals on redis I see that tree data are possible, like root object and nested inserted objects.

But when in laravel 9.4 app with predis/predis 2.1 I write data with

  1. Redis::set('key', serialize( $data ) );

method and in phpRedisAdmin I see that all written data are written (with redis=>prefix parameter from config/database.php) on the same level,
but not root object and nested inserted objects.

Which methods have I to use for data wring and tools to view data in tree structure ?

UPDATED BLOCK 1:
I copypasted sample code into my app :

  1. $data = [ 'name' => 'John Doe', 'email' => 'johndoe@example.com', 'address' => [ 'street' => '123 Main St', 'city' => 'Anytown', 'state' => 'CA', 'zip' => '12345' ]
  2. ];
  3. Redis::hmset('user:1', $data); // Error is pointing to this 173 line

but I got error :

  1. php artisan job:dispatchNow ArticlesCachingJob
  2. ErrorException
  3. Array to string conversion
  4. at vendor/predis/predis/src/Connection/StreamConnection.php:365
  5. 361
  6. 362 foreach ($arguments as $argument) {
  7. 363 \Log::info( ' $argument::');
  8. 364 \Log::info( $argument);
  9. 365 $arglen = strlen(strval($argument));
  10. 366 $buffer .= "${$arglen}\r\n{$argument}\r\n";
  11. 367 }
  12. 368
  13. 369 $this->write($buffer);
  14. +8 vendor frames
  15. 9 app/Library/Services/ArticlesRedisCaching.php:173
  16. Illuminate\Support\Facades\Facade::__callStatic()

I tried to debug code and added 2 logging lines into vendor/predis/predis/src/Connection/StreamConnection.php file:

  1. public function writeRequest(CommandInterface $command) // line 352
  2. {
  3. $commandID = $command->getId();
  4. $arguments = $command->getArguments();
  5. $cmdlen = strlen($commandID);
  6. $reqlen = count($arguments) + 1;
  7. $buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";
  8. foreach ($arguments as $argument) {
  9. \Log::info( ' $argument::');
  10. \Log::info( $argument);
  11. $arglen = strlen(strval($argument));
  12. $buffer .= "${$arglen}\r\n{$argument}\r\n";
  13. }
  14. $this->write($buffer);
  15. }
  16. 2023-02-20 07:27:04] local.INFO: $argument::
  17. [2023-02-20 07:27:04] local.INFO: _votes_db_user:1
  18. [2023-02-20 07:27:04] local.INFO: $argument::
  19. [2023-02-20 07:27:04] local.INFO: name
  20. [2023-02-20 07:27:04] local.INFO: $argument::
  21. [2023-02-20 07:27:04] local.INFO: John Doe
  22. [2023-02-20 07:27:04] local.INFO: $argument::
  23. [2023-02-20 07:27:04] local.INFO: email
  24. [2023-02-20 07:27:04] local.INFO: $argument::
  25. [2023-02-20 07:27:04] local.INFO: johndoe@example.com
  26. [2023-02-20 07:27:04] local.INFO: $argument::
  27. [2023-02-20 07:27:04] local.INFO: address
  28. [2023-02-20 07:27:04] local.INFO: $argument::
  29. [2023-02-20 07:27:04] local.INFO: array (
  30. 'street' => '123 Main St',
  31. 'city' => 'Anytown',
  32. 'state' => 'CA',
  33. 'zip' => '12345',
  34. )
  35. [2023-02-20 07:27:04] local.ERROR: Array to string conversion {"exception":"[object] (ErrorException(code: 0): Array to string conversion at /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Connection/StreamConnection.php:365)
  36. [stacktrace]
  37. #0 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php(266): Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError()
  38. #1 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->Illuminate\\Foundation\\Bootstrap\\{closure}()
  39. #2 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Connection/StreamConnection.php(365): strval()
  40. #3 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Connection/AbstractConnection.php(110): Predis\\Connection\\StreamConnection->writeRequest()
  41. #4 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Client.php(318): Predis\\Connection\\AbstractConnection->executeCommand()
  42. #5 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Client.php(301): Predis\\Client->executeCommand()
  43. #6 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(116): Predis\\Client->__call()
  44. #7 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(216): Illuminate\\Redis\\Connections\\Connection->command()
  45. #8 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/RedisManager.php(276): Illuminate\\Redis\\Connections\\Connection->__call()
  46. #9 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Illuminate\\Redis\\RedisManager->__call()
  47. #10 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/app/Library/Services/ArticlesRedisCaching.php(173): Illuminate\\Support\\Facades\\Facade::__callStatic()

As you see strval can not work with array.

  1. I wrapped 'address' array with serialize method - it worked ok and that is what I see in phpRedisAdmin : https://prnt.sc/BMnRev9HDwZz

  2. Have I to wrap all subarray with serialize method ?

  3. Searching in net I found some hints that HMSET is considered deprecated. I tried hset, but it raised the same Array to string conversion error
    in both cases with serialize( or without it

  4. I have

    Redis server v=5.0.7 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=66bd62

under kubuntu 20.04

UPDATED BLOCK 2:

  1. I tried 2 ways :
  2. $data = [ 'name' => 'John Doe', 'email' => 'johndoe@example.com', 'address' => (object)[ 'street' => '123 Main St', 'city' => 'Anytown', 'state' => 'CA', 'zip' => '12345' ]
  3. ];
  4. Redis::hset('user:1', $data);

and I got :

  1. Array to string conversion
  2. at vendor/predis/predis/src/Connection/StreamConnection.php:365
  3. 361
  4. 362 foreach ($arguments as $argument) {
  5. 363 //\Log::info( ' $argument::');
  6. 364 //\Log::info( $argument);
  7. 365 $arglen = strlen(strval($argument));
  8. 366 $buffer .= "${$arglen}\r\n{$argument}\r\n";
  9. 367 }
  10. 368
  11. 369 $this->write($buffer);
  12. +8 vendor frames
  13. 9 app/Library/Services/ArticlesRedisCaching.php:176
  14. Illuminate\Support\Facades\Facade::__callStatic()
  15. 10 app/Jobs/ArticlesCachingJob.php:52
  16. App\Library\Services\ArticlesRedisCaching::addArticleToCaching()

and second :

  1. $data = [ 'name' => 'John Doe', 'email' => 'johndoe@example.com', 'address' => [ 'street' => '123 Main St', 'city' => 'Anytown', 'state' => 'CA', 'zip' => '12345' ]
  2. ];
  3. Redis::hset('user:1', (object)$data);

and error again :

  1. Object of class stdClass could not be converted to string
  2. at vendor/predis/predis/src/Connection/StreamConnection.php:365
  3. 361
  4. 362 foreach ($arguments as $argument) {
  5. 363 //\Log::info( ' $argument::');
  6. 364 //\Log::info( $argument);
  7. 365 $arglen = strlen(strval($argument));
  8. 366 $buffer .= "${$arglen}\r\n{$argument}\r\n";
  9. 367 }
  10. 368
  11. 369 $this->write($buffer);
  12. +8 vendor frames
  13. 9 app/Library/Services/ArticlesRedisCaching.php:176
  14. Illuminate\Support\Facades\Facade::__callStatic()

looks like any value must be string(or serialized string) ?

Thank you!

答案1

得分: 1

以下是代码部分的翻译:

  1. After some tests I found a valid way top save/read structured data with redis as :
  2. $articleArray = self::serializeArray($article->toArray());
  3. Redis::hmset($redisUniqueKey, $articleArray);
  4. ...
  5. protected static function serializeArray(?array $data): array
  6. {
  7. foreach ($data as $fieldName => $fieldValue) {
  8. if (is_array($fieldValue)) {
  9. $data[$fieldName] = serialize($fieldValue);
  10. }
  11. }
  12. return $data;
  13. }
  14. and reading :
  15. $cachedArticle = self::unserializeArray(Redis::HGETALL($redisUniqueKey));
  16. ...
  17. protected static function unserializeArray(?array $data): array
  18. {
  19. foreach ($data as $fieldName => $fieldValue) {
  20. if (isSerialized($fieldValue)) {
  21. $data[$fieldName] = unserialize($fieldValue);
  22. }
  23. }
  24. return $data;
  25. }
  26. That works for me with data I test.
英文:

After some tests I found a valid way top save/read structured data with redis as :

  1. $articleArray = self::serializeArray($article->toArray());
  2. Redis::hmset($redisUniqueKey, $articleArray);
  3. ...
  4. protected static function serializeArray(?array $data): array
  5. {
  6. foreach ($data as $fieldName => $fieldValue) {
  7. if (is_array($fieldValue)) {
  8. $data[$fieldName] = serialize($fieldValue);
  9. }
  10. }
  11. return $data;
  12. }

and reading :

  1. $cachedArticle = self::unserializeArray(Redis::HGETALL($redisUniqueKey));
  2. ...
  3. protected static function unserializeArray(?array $data): array
  4. {
  5. foreach ($data as $fieldName => $fieldValue) {
  6. if (isSerialized($fieldValue)) {
  7. $data[$fieldName] = unserialize($fieldValue);
  8. }
  9. }
  10. return $data;
  11. }

That works for me with data I test.

huangapple
  • 本文由 发表于 2023年2月16日 15:47:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75469204.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定