3

dropwizard と jdbi で JSONB データ型を使用して、postgresql 9.4 データベースに JSON を保存しようとしています。データを保存することはできますが、json が 1 つのレベルより深くなると、json はネストされた json ではなく文字列に変換されます。

たとえば、次のjson

{
  "type":"unit",
  "nested": {
    "key":"embedded"
  }
}

実際には次のように保存されます

{
  "type":"unit",
  "nested":"{key=embedded}"
}

私のDAOのメソッドシグネチャは

@SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
protected abstract void createJson(@Bind("id") String id, @Bind("content") Map content);

明らかに何か問題がありますが、このネストされたデータを保存する正しい方法を理解できないようです。

4

2 に答える 2

4

を使用PGObjectして、Java で JSONB データ型を構築できます。このようにして、SQL の一部としての特別な処理を回避できます。

PGobject dataObject = new PGobject();
dataObject.setType("jsonb");
dataObject.setValue(value.toString());

オブジェクトをツリーに変換し、ArgumentFactory を使用してそれを PGobject に変換することを含む完全な例は、次のようになります。

public class JsonbTest {

    @Test
    public void tryoutjson() throws Exception {
        final DBI dbi = new DBI("jdbc:postgresql://localhost:5432/sighting", "postgres", "admin");
        dbi.registerArgumentFactory(new ObjectNodeArgumentFactor());
        Sample sample = dbi.onDemand(Sample.class);

        ObjectMapper mapper = new ObjectMapper();

        int id = 2;

        User user = new User();
        user.emailaddress = "me@home.com";
        user.posts = 123;
        user.username = "test";

        sample.insert(id, mapper.valueToTree(user));
    }

    public static class User {
        public String username, emailaddress;
        public long posts;
    }

    public interface Sample {
        @SqlUpdate("INSERT INTO sample (id, data) VALUES (:id, :data)")
        int insert(@Bind("id") long id, @Bind("data") TreeNode data);
    }

    public static class ObjectNodeArgumentFactor implements ArgumentFactory<TreeNode> {

        private static class ObjectNodeArgument implements Argument {
            private final PGobject value;

            private ObjectNodeArgument(PGobject value) {
                this.value = value;
            }

            @Override
            public void apply(int position,
                              PreparedStatement statement,
                              StatementContext ctx) throws SQLException {
                statement.setObject(position, value);
            }
        }

        @Override
        public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
            return value instanceof TreeNode;
        }

        @Override
        public Argument build(Class<?> expectedType, TreeNode value, StatementContext ctx) {
            try {
                PGobject dataObject = new PGobject();
                dataObject.setType("jsonb");
                dataObject.setValue(value.toString());
                return new ObjectNodeArgument(dataObject);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
于 2015-09-11T21:14:01.237 に答える
1

writeValueAsString(Map)Jackson ObjectMapperを呼び出して取得した文字列を渡すことで、これを解決できました。私の createJson メソッドは次のようになりました。

@SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
public abstract void createJson(@Bind("id")String id, @Bind("content")String content);

マッパーを作成して、渡す文字列を取得しました。

private ObjectMapper mapper = Jackson.newObjectMapper();

そして、次のように呼び出します。

mapper.writeValueAsString(map);

これにより、探していたネストされたjsonが得られました。

于 2015-09-08T19:33:44.997 に答える