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

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

How with predis to write data in tree structure?

问题

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

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

$data = [
    'name' => 'John Doe',
    'email' => 'johndoe@example.com',
    'address' => [
        'street' => '123 Main St',
        'city' => 'Anytown',
        'state' => 'CA',
        'zip' => '12345'
    ]
];

Redis::hmset('user:1', $data); // 错误指向了这一行173

但我收到了错误:

php artisan job:dispatchNow ArticlesCachingJob

ErrorException

Array to string conversion

 vendor/predis/predis/src/Connection/StreamConnection.php 的第365行
  1. 我在代码中进行了调试,并在vendor/predis/predis/src/Connection/StreamConnection.php文件中添加了2行日志记录:
public function writeRequest(CommandInterface $command) // 第352行
{
    $commandID = $command->getId();
    $arguments = $command->getArguments();

    $cmdlen = strlen($commandID);
    $reqlen = count($arguments) + 1;

    $buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";

    foreach ($arguments as $argument) {
        \Log::info(' $argument::');
        \Log::info($argument);
        $arglen = strlen(strval($argument));
        $buffer .= "${$arglen}\r\n{$argument}\r\n";
    }

    $this->write($buffer);
}
  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:

我尝试了两种方法:

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

Redis::hset('user:1', $data);

$data = [
    'name' => 'John Doe',
    'email' => 'johndoe@example.com',
    'address' => [
        'street' => '123 Main St',
        'city' => 'Anytown',
        'state' => 'CA',
        'zip' => '12345'
    ]
];

Redis::hset('user:1', (object)$data);

两者都导致错误:

Array to string conversion

 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

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 :

$data = [  'name' => 'John Doe',  'email' => 'johndoe@example.com',  'address' => [    'street' => '123 Main St',    'city' => 'Anytown',    'state' => 'CA',    'zip' => '12345'  ]
];

Redis::hmset('user:1', $data);  // Error is pointing to this 173 line

but I got error :

php artisan job:dispatchNow ArticlesCachingJob

ErrorException

Array to string conversion

at vendor/predis/predis/src/Connection/StreamConnection.php:365
361▕
362▕         foreach ($arguments as $argument) {
363▕ \Log::info( ' $argument::');
364▕ \Log::info( $argument);
➜ 365▕             $arglen = strlen(strval($argument));
366▕             $buffer .= "${$arglen}\r\n{$argument}\r\n";
367▕         }
368▕
369▕         $this->write($buffer);

+8 vendor frames
9   app/Library/Services/ArticlesRedisCaching.php:173
Illuminate\Support\Facades\Facade::__callStatic()

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

    public function writeRequest(CommandInterface $command) // line 352
    {
        $commandID = $command->getId();
        $arguments = $command->getArguments();

        $cmdlen = strlen($commandID);
        $reqlen = count($arguments) + 1;

        $buffer = "*{$reqlen}\r\n${$cmdlen}\r\n{$commandID}\r\n";

        foreach ($arguments as $argument) {
\Log::info( ' $argument::');
\Log::info( $argument);
            $arglen = strlen(strval($argument));
            $buffer .= "${$arglen}\r\n{$argument}\r\n";
        }

        $this->write($buffer);
    }


2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: _votes_db_user:1
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: name
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: John Doe
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: email
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: johndoe@example.com
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: address
[2023-02-20 07:27:04] local.INFO:  $argument::
[2023-02-20 07:27:04] local.INFO: array (
  'street' => '123 Main St',
  'city' => 'Anytown',
  'state' => 'CA',
  'zip' => '12345',
)
[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)
[stacktrace]
#0 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php(266): Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError()
#1 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->Illuminate\\Foundation\\Bootstrap\\{closure}()
#2 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Connection/StreamConnection.php(365): strval()
#3 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Connection/AbstractConnection.php(110): Predis\\Connection\\StreamConnection->writeRequest()
#4 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Client.php(318): Predis\\Connection\\AbstractConnection->executeCommand()
#5 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/predis/predis/src/Client.php(301): Predis\\Client->executeCommand()
#6 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(116): Predis\\Client->__call()
#7 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/Connections/Connection.php(216): Illuminate\\Redis\\Connections\\Connection->command()
#8 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Redis/RedisManager.php(276): Illuminate\\Redis\\Connections\\Connection->__call()
#9 /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Illuminate\\Redis\\RedisManager->__call()
#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:

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

Redis::hset('user:1',  $data);

and I got :

  Array to string conversion

  at vendor/predis/predis/src/Connection/StreamConnection.php:365
    361▕
    362▕         foreach ($arguments as $argument) {
    363▕ //\Log::info( ' $argument::');
    364▕ //\Log::info( $argument);
  ➜ 365▕             $arglen = strlen(strval($argument));
    366▕             $buffer .= "${$arglen}\r\n{$argument}\r\n";
    367▕         }
    368▕
    369▕         $this->write($buffer);

      +8 vendor frames
  9   app/Library/Services/ArticlesRedisCaching.php:176
      Illuminate\Support\Facades\Facade::__callStatic()

  10  app/Jobs/ArticlesCachingJob.php:52
      App\Library\Services\ArticlesRedisCaching::addArticleToCaching()

and second :

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

and error again :

  Object of class stdClass could not be converted to string

  at vendor/predis/predis/src/Connection/StreamConnection.php:365
    361▕ 
    362▕         foreach ($arguments as $argument) {
    363▕ //\Log::info( ' $argument::');
    364▕ //\Log::info( $argument);
  ➜ 365▕             $arglen = strlen(strval($argument));
    366▕             $buffer .= "${$arglen}\r\n{$argument}\r\n";
    367▕         }
    368▕ 
    369▕         $this->write($buffer);

      +8 vendor frames 
  9   app/Library/Services/ArticlesRedisCaching.php:176
      Illuminate\Support\Facades\Facade::__callStatic()

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

Thank you!

答案1

得分: 1

以下是代码部分的翻译:

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

    $articleArray = self::serializeArray($article->toArray());
    Redis::hmset($redisUniqueKey, $articleArray);
    ...


    protected static function serializeArray(?array $data): array
    {
        foreach ($data as $fieldName => $fieldValue) {
            if (is_array($fieldValue)) {
                $data[$fieldName] = serialize($fieldValue);
            }
        }

        return $data;
    }

and reading :

    $cachedArticle = self::unserializeArray(Redis::HGETALL($redisUniqueKey));
    ...
    protected static function unserializeArray(?array $data): array
    {
        foreach ($data as $fieldName => $fieldValue) {
            if (isSerialized($fieldValue)) {
                $data[$fieldName] = unserialize($fieldValue);
            }
        }
    
        return $data;
    }

That works for me with data I test.
英文:

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

$articleArray = self::serializeArray($article->toArray());
Redis::hmset($redisUniqueKey, $articleArray);
...


protected static function serializeArray(?array $data): array
{
    foreach ($data as $fieldName => $fieldValue) {
        if (is_array($fieldValue)) {
            $data[$fieldName] = serialize($fieldValue);
        }
    }

    return $data;
}

and reading :

$cachedArticle = self::unserializeArray(Redis::HGETALL($redisUniqueKey));
...
protected static function unserializeArray(?array $data): array
{
    foreach ($data as $fieldName => $fieldValue) {
        if (isSerialized($fieldValue)) {
            $data[$fieldName] = unserialize($fieldValue);
        }
    }

    return $data;
}

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:

确定