Итерация по массиву jsonb: оператор не существует: имя ->> неизвестно
В игре для Android пользователи могут войти через Google+, Facebook, Twitter:
Когда приложение подключается к серверу PostgreSQL/PHP, оно отправляет список идентификаторов социальных сетей, и я сохраняю их как sid
столбец в social
Таблица:
create table social (
sid varchar(255) not null,
auth char(32) not null,
social integer not null check (0 <= social and social <= 6),
given varchar(255) not null check (given ~ '\S'),
photo varchar(255) null check (photo ~* '^https?://...'),
stamp timestamp not null,
ip inet not null,
uid integer not null references users on delete cascade,
primary key(sid, social)
);
В другой таблице под названием users
Я сохраняю автоинкрементные идентификаторы пользователей как uid
колонки и использовать его для отслеживания своих игр, достижений, статистики игрока:
create table users (
uid serial primary key,
created timestamp not null,
stamp timestamp not null,
banned_until timestamp null,
banned_reason varchar(255) null
);
В сценарии входа в PHP я пытаюсь объединить социальные учетные записи, когда это возможно -
взяв все полученные sids, найдя соответствующие uid, а затем взяв самый низкий найденный uid и обновив записи в social
таблица, чтобы использовать этот самый низкий UID.
Это уже хорошо работает в PHP, но теперь я пытаюсь переместить функциональность слияния в хранимую функцию PostgreSQL:
CREATE OR REPLACE FUNCTION merge_users(
IN in_users jsonb,
IN in_ip inet,
OUT out_uid integer) AS
$func$
DECLARE
user jsonb;
BEGIN
SELECT MIN(uid) INTO out_uid FROM social
WHERE sid IN (SELECT u->>'sid' FROM JSONB_ARRAY_ELEMENTS(in_users) u);
IF FOUND THEN
UPDATE words_social SET uid=out_uid
WHERE sid IN (SELECT u->>'sid' FROM JSONB_ARRAY_ELEMENTS(in_users) u);
ELSE
INSERT INTO words_users (created, stamp)
VALUES (current_timestamp, current_timestamp)
RETURNING uid INTO out_uid;
END IF;
FOR user IN SELECT * FROM JSONB_ARRAY_ELEMENTS(in_users)
LOOP
RAISE NOTICE 'user sid = %', user->>'sid';
UPDATE social SET
auth = user->'auth',
social = user->'social',
given = user->'given',
photo = user->'photo',
stamp = TO_TIMESTAMP(user->'stamp'),
ip = in_ip,
uid = out_uid
WHERE sid = user->>'sid';
IF NOT FOUND THEN
INSERT INTO social (
sid,
auth,
social,
given,
photo,
stamp,
ip,
uid
) VALUES (
user->'sid',
user->'auth',
user->'social',
user->'given',
user->'photo',
TO_TIMESTAMP(user->'stamp'),
in_ip,
out_uid
);
END IF;
END LOOP;
END
$func$ LANGUAGE plpgsql;
К сожалению, приведенный выше код выводит сообщение об ошибке синтаксиса:
# select * from merge_users(
'[{"sid":"12345284239407942","auth":"ddddc1808197a1161bc22dc307accccc","social":3,"given":"Alexander1","family":"Farber","photo":"https:\/\/graph.facebook.com\/10154284239407942\/picture?type=large","place":"Bochum, Germany","female":0,"stamp":1450102770},{"sid":"54321284239407942","auth":"ddddc1808197a1161bc22dc307abbbbb","social":4,"given":"Alexander2","family":"Farber","photo":null,"place":"Bochum, Germany","female":0,"stamp":1450102800}]'::jsonb);
NOTICE: min uid = <NULL>
ERROR: operator does not exist: name ->> unknown
LINE 1: SELECT user->>'sid'
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
QUERY: SELECT user->>'sid'
CONTEXT: PL/pgSQL function words_merge_users(jsonb) line 15 at RAISE
Я пытался добавить ::jsonb
в u
а также user
в приведенном выше коде, но это не помогло.