2015-09-08 76 views
1

我正在嘗試使用帶有dropwizard和jdbi的JSONB數據類型將json存儲在postgresql 9.4數據庫中。我能夠存儲數據,但是如果我的json比單層更深,json會變成一個字符串,而不是嵌套的json。需要幫助在postgresql中使用jdbi存儲嵌套的json

例如,下面的JSON

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

實際上被存儲爲

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

的方法簽名吾道

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

我顯然有一些錯誤,但我似乎無法找出存儲此嵌套數據的正確方法。

回答

1

我能通過在Jackson ObjectMapper上調用writeValueAsString(Map)來獲得一個字符串來解決這個問題。我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我在尋找。

1

您可以使用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 = "[email protected]"; 
     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); 
      } 
     } 
    } 

}