Java 如何在MongoDb中使用jackson将日期字段存储为ISODate()
我正在尝试使用fasterxml持久化mongo集合中具有Java 如何在MongoDb中使用jackson将日期字段存储为ISODate(),java,mongodb,jackson,Java,Mongodb,Jackson,我正在尝试使用fasterxml持久化mongo集合中具有java.util.Date字段的java对象。 问题是objectMapper的默认性质是将日期存储为NumberLong类型 例如,java.util.Date类型的
java.util.Date
字段的java对象。
问题是objectMapper的默认性质是将日期存储为NumberLong类型
例如,java.util.Date类型的
字段存储如下:
“createdTime”:数字长(“1427728445176”)
我想以mongo Shell中提供的ISODate格式存储它
现在,我知道有一种方法可以格式化对象映射器,以字符串dateformat存储日期。
但我只寻找ISODate()格式
例如
“createdTime”:ISODate(“2015-01-20T16:39:42.132Z”)
有办法吗?
请告知大师。
提前感谢您的帮助。您需要的是。如果将其导入类路径,则可以在映射器上执行以下操作,将其写入所需的时间戳:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
mapper.writeValueAsString(date);
如有必要,您可以使用POJO替换上述代码示例中的date
编辑:
看起来您真正想要的是自定义序列化程序。看起来是这样的:
public class IsoDateSerializer extends JsonSerializer<DateTime> {
@Override
public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) {
String isoDate = ISODateTimeFormat.dateTime().print(value);
jgen.writeRaw("ISODATE(\"" + isoDate + "\")");
}
或者使用注释在函数上指定它
@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);
}
根据user@mmx73的请求,我正在为客户日期反序列化程序添加代码
public class IsoDateDeSerializer extends JsonDeserializer<Date> {
@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;
}
}
公共类IsoDateDeSerializer扩展JsonDeserializer{
@凌驾
公共日期反序列化(JsonParser JsonParser,反序列化上下文反序列化上下文)
抛出IOException、JsonProcessingException{
ObjectCodec oc=jsonParser.getCodec();
JsonNode=oc.readTree(jsonParser);
字符串dateValue=node.get(“$date”).asText();
//DateFormat df=新的简化格式(“yyyy-MM-dd'T'HH:MM:ss'Z'”;
DateFormat df=新的SimpleDataFormat(“yyyy-MM-dd'T'HH:MM:ss.SSS'Z'”);
日期=空;
试一试{
date=df.parse(dateValue);
}捕获(解析异常){
e、 printStackTrace();
}
返回日期;
}
}
这些答案都没有达到我的目的。我遇到了麻烦,因为当我将JSON字符串序列化到MongoDB时,它被存储为字符串。一个格式很好的字符串,但仍然是一个字符串
我使用com.fasterxml.jackson.databind.ObjectMapper将我的对象转换为JSON或从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>(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>(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;
}
结果如下:
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
MongoDatabase db = getDatabase();
Document d = Document.parse(json);
db.getCollection(bucket).insertOne(d);
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(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:<long integer for milliseconds>}
// 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);
}
}
});
/**
* 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);
}
请注意,将发送到MONGODB的JSON定义了包含名为“$date”的字段的值。这告诉MongoDB这似乎是一个日期对象
当我看Mongo时,我看到以下内容:
"importDate" : ISODate("2016-05-18T18:55:07Z")
现在,我可以以日期而不是字符串的形式访问该字段
要向Mongo添加编码的JSON字符串,我的代码如下:
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
MongoDatabase db = getDatabase();
Document d = Document.parse(json);
db.getCollection(bucket).insertOne(d);
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(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:<long integer for milliseconds>}
// 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);
}
}
});
/**
* 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);
}
在本例中,“json”是编码的json字符串。因为它来自一个JSON字符串,除非它推断出这一点,否则它无法知道类型,这就是为什么我们需要“$date”部分。“bucket”只是一个字符串,指示要使用哪个表
作为旁注,我发现如果我从Mongo中提取一个BSON对象,并通过调用doc.toJson()将其转换为JSON字符串(其中doc是从查询返回的org.bison.Document类型),则date对象将以长值而不是格式化的文本字符串存储。我没有检查是否可以在格式化数据后以这种方式将数据推送到mongo中,但是,您可以修改上面显示的反序列化程序以支持此操作,如下所示:
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
MongoDatabase db = getDatabase();
Document d = Document.parse(json);
db.getCollection(bucket).insertOne(d);
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(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:<long integer for milliseconds>}
// 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);
}
}
});
/**
* 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);
}
testModule.addDeserializer(Date.class,新StdDeserializer(Date.class){
私有静态最终长serialVersionUID=1L;
@凌驾
公共日期反序列化(JsonParser jp,反序列化上下文dc)引发IOException,JsonProcessingException{
JsonNode tree=jp.readValueAsTree();
SimpleDataFormat dateFormat=新的SimpleDataFormat(“yyyy-MM-dd'T'HH:MM:ssZ”);
试一试{
//Mongo将返回看起来更像:
//{$date:}
//所以也要处理好。
JsonNode dateNode=tree.get(“$date”);
if(dateNode!=null){
字符串textValue=dateNode.textValue();
如果(!Util.IsNullOrEmpty(textValue)){
返回ISODateTimeFormat.dateTime().parseDateTime(textValue.toDate();
}
返回Util.MillisToDate(dateNode.asLong());
}
返回null;
}捕获(可丢弃的t){
Util.LogIt(“异常:+t.getMessage());
抛出新的IOException(t.getMessage(),t);
}
}
});
您可以将毫秒转换为日期或日期时间,如下所示:
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
MongoDatabase db = getDatabase();
Document d = Document.parse(json);
db.getCollection(bucket).insertOne(d);
testModule.addDeserializer(Date.class, new StdDeserializer<Date>(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:<long integer for milliseconds>}
// 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);
}
}
});
/**
* 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);
}
/**
*将毫秒转换为日期时间。如果为零或负,则返回
*空。
*
*@param毫秒
*@返回
*/
公共静态日期毫秒(最后的长毫秒){
如果(毫秒<1){
返回null;
}
日历=Calendar.getInstance();
calendar.setTimeInMillis(毫秒);
返回calendar.getTime();
}
公共静态日期时间MillisToDateTime(最后的长毫秒){
如果(毫秒<1){
返回null;
}
返回新的日期时间(毫秒);
}
以防收到如下消息
com.fasterxml.jackson.core.jsongGenerationException:无法写入字段名,需要值
确保在接受的答案中使用
writeRawValue
。这将正确结束字段,否则下一个要序列化的字段可能会抛出此错误。您可以通过读取/写入bson而不是json来解决此问题。下面是一个测试类:
package com.nagra.jongo.mapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import de.undercouch.bson4jackson.BsonFactory;
import de.undercouch.bson4jackson.deserializers.BsonDateDeserializer;
import de.undercouch.bson4jackson.serializers.BsonDateSerializer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Date;
/**
* Uses Bson4Jackson 2.9.0
*
* <!-- https://mvnrepository.com/artifact/de.undercouch/bson4jackson -->
* <dependency>
* <groupId>de.undercouch</groupId>
* <artifactId>bson4jackson</artifactId>
* <version>2.9.2</version>
* </dependency>
*/
public class ObjectMapperTest {
private ObjectMapper mapper = new ObjectMapper(new BsonFactory());
private static class WrappedDate {
private Date Date = new Date(0);
public WrappedDate() {
}
public Date getDate() {
return Date;
}
public void setDate(Date Date) {
this.Date = Date;
}
}
@Before
public void setUp() {
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new BsonDateSerializer());
module.addDeserializer(Date.class, new BsonDateDeserializer());
mapper.registerModule(module);
}
@Test
public void testDate() throws IOException {
WrappedDate date = new WrappedDate();
byte[] b = mapper.writeValueAsBytes(date);
WrappedDate i = mapper.readValue(b, WrappedDate.class);
Assert.assertEquals(date.getDate(), i.getDate());
System.out.println(i.getDate());
}}
package com.nagra.jongo.mapper;
导入com.fasterxml.jackson.databi