如何使用MongoDb中的jackson将Date字段存储为ISODate()

我试图使用fastxml jackson在mongo集合中持久保存java.util.Date字段的java对象。 问题是objectMapper的默认性质是将Date存储为NumberLong类型。

例如, java.util.Date类型的createdTime字段存储如下:

"createdTime" : NumberLong("1427728445176")

我想将它存储在mongo Shell中可用的ISODate格式中。

现在,我知道有办法格式化对象映射器以将日期存储在字符串dateformat中。 但我只是在寻找ISODate()格式。

例如"createdTime" : ISODate("2015-01-20T16:39:42.132Z")

有没有办法做到这一点 ? 请告知大师。 在此先感谢您的帮助。

你需要的是Jackson Joda模块 。 如果将其导入到类路径中,则可以在映射器上执行以下操作,将其写为所需的时间戳:

 ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JodaModule()); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true); mapper.writeValueAsString(date); 

您可以根据需要将上面的代码示例中的date替换为POJO。

编辑:看起来你真正想要的是一个自定义序列化器。 这看起来像这样:

 public class IsoDateSerializer extends JsonSerializer { @Override public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) { String isoDate = ISODateTimeFormat.dateTime().print(value); jgen.writeRaw("ISODATE(\"" + isoDate + "\")"); } 

然后,您将在映射器上为所有DateTime类型注册它

 mapper.addSerializer(DateTime.class, new IsoDateSerializer()); 

或使用注释在函数上指定它

 @JsonSerializer(using = IsoDateSerializer.class) public DateTime createdTime; 

我能够将日期字符串序列化为ISODate格式。 我写了一个客户日期序列化器,如下所示。

 public void serialize(Date date, JsonGenerator jgen, SerializerProvider provider) throws IOException { String dateValue = getISODateString(date); String text = "{ \"$date\" : \""+ dateValue +"\"}"; jgen.writeRawValue(text); } 

根据用户@mmx73的要求,我正在为客户Date DeSeriaizer添加代码。

 public class IsoDateDeSerializer extends JsonDeserializer { @Override public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { ObjectCodec oc = jsonParser.getCodec(); JsonNode node = oc.readTree(jsonParser); String dateValue = node.get("$date").asText(); //DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); Date date = null; try { date = df.parse(dateValue); } catch (ParseException e) { e.printStackTrace(); } return date; } } 

这些答案都没有完成我想要的。 我遇到了麻烦,因为当我将JSON字符串序列化为MongoDB时,它被存储为String。 一个格式很好的字符串,但字符串也是如此。

我使用com.fasterxml.jackson.databind.ObjectMapper将我的对象转换为JSON或从JSON转换,我想继续使用这个类。 我有以下方法:

 public enum JsonIntent {NONE, MONGODB}; public static ObjectMapper getMapper(final JsonIntent intent) { ObjectMapper mapper = new ObjectMapper(); // Setting to true saves the date as NumberLong("1463597707000") // Setting to false saves the data as "2016-05-18T19:30:52.000+0000" mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); mapper.registerModule(new JodaModule()); if (intent == JsonIntent.MONGODB) { // If you want a date stored in MONGO as a date, then you must store it in a way that MONGO // is able to deal with it. SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null, null, null)); testModule.addSerializer(Date.class, new StdSerializer(Date.class) { private static final long serialVersionUID = 1L; @Override public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException { try { if (value == null) { jgen.writeNull(); } else { jgen.writeStartObject(); jgen.writeFieldName("$date"); String isoDate = ISODateTimeFormat.dateTime().print(new DateTime(value)); jgen.writeString(isoDate); jgen.writeEndObject(); } } catch (Exception ex) { Logger.getLogger(JsonUtil.class.getName()).log(Level.SEVERE, "Couldn't format timestamp " + value + ", writing 'null'", ex); jgen.writeNull(); } } }); testModule.addDeserializer(Date.class, new StdDeserializer(Date.class) { private static final long serialVersionUID = 1L; @Override public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException { JsonNode tree = jp.readValueAsTree(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); try { return ISODateTimeFormat.dateTime().parseDateTime(tree.get("$date").textValue()).toDate(); } catch (Throwable t) { throw new IOException(t.getMessage(), t); } } }); mapper.registerModule(testModule); } return mapper; } 

现在,我可以运行以下测试代码:

 BObjectMapper mapper = getMapper(JsonUtil.JsonIntent.NONE); Date d1 = new Date(); String v = mapper.writeValueAsString(d1); System.out.println("Joda Mapping: " + v); Date d2 = mapper.readValue(v, Date.class); System.out.println("Decoded Joda: " + d2); mapper = getMapper(JsonUtil.JsonIntent.MONGODB); v = mapper.writeValueAsString(d1); System.out.println("Mongo Mapping: " + v); d2 = mapper.readValue(v, Date.class); System.out.println("Decoded Mongo: " + d2); 

输出如下:

 Joda Mapping: "2016-06-13T14:58:11.937+0000" Decoded Joda: Mon Jun 13 10:58:11 EDT 2016 Mongo Mapping: {"$date":"2016-06-13T10:58:11.937-04:00"} Decoded Mongo: Mon Jun 13 10:58:11 EDT 2016 

请注意,将发送到MONGODB的JSON定义包含名为“$ date”的字段的值。 这告诉MongoDB它似乎是一个日期对象。

当我看到Mongo时,我看到以下内容:

 "importDate" : ISODate("2016-05-18T18:55:07Z") 

现在,我可以将该字段作为日期而不是字符串来访问。

要将编码的JSON字符串添加到Mongo,我的代码如下:

 MongoDatabase db = getDatabase(); Document d = Document.parse(json); db.getCollection(bucket).insertOne(d); 

在这种情况下,“json”是编码的JSON字符串。 因为它来自JSON字符串,除非它推断出它,否则它无法知道类型,这就是我们需要“$ date”部分的原因。 “bucket”只是一个字符串,表示要使用的表。

作为旁注,我发现如果我从Mongo中提取BSON对象并通过调用doc.toJson()将其转换为JSON字符串(其中doc是从查询返回的org.bison.Document类型), date对象使用long值而不是格式化的文本字符串存储。 我没有检查是否可以在格式化后以这种方式将数据推送到mongo,但是,您可以修改上面显示的反序列化器以支持此操作,如下所示:

  testModule.addDeserializer(Date.class, new StdDeserializer(Date.class) { private static final long serialVersionUID = 1L; @Override public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException { JsonNode tree = jp.readValueAsTree(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); try { // Mongo will return something that looks more like: // {$date:} // so handle that as well. JsonNode dateNode = tree.get("$date"); if (dateNode != null) { String textValue = dateNode.textValue(); if (!Util.IsNullOrEmpty(textValue)) { return ISODateTimeFormat.dateTime().parseDateTime(textValue).toDate(); } return Util.MillisToDate(dateNode.asLong()); } return null; } catch (Throwable t) { Util.LogIt("Exception: " + t.getMessage()); throw new IOException(t.getMessage(), t); } } }); 

您可以将毫秒转换为Date或DateTime,如下所示:

  /** * Convert milliseconds to a date time. If zero or negative, just return * null. * * @param milliseconds * @return */ public static Date MillisToDate(final long milliseconds) { if (milliseconds < 1) { return null; } Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(milliseconds); return calendar.getTime(); } public static DateTime MillisToDateTime(final long milliseconds) { if (milliseconds < 1) { return null; } return new DateTime(milliseconds); } 

万一你得到一些消息

com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value

确保在接受的答案中使用writeRawValue 。 这会正确结束字段,否则下一个要序列化的字段可能会抛出此错误。