草庐IT

json - 严格模式下的MongoDB日期格式

coder 2023-11-05 原文

  1. 使用 MongoDB java 驱动程序,在 Document 上应用 toJson() 方法将获得此文档的 JSON 表示形式,并将 JsonMode 设置为 STRICT。 以下纪元格式用于日期:{ "$date": "dateAsMilliseconds"}

  2. 使用 mongoexport,我们得到一个 ISO-8601 格式。

  3. 在官方文档 ( https://docs.mongodb.com/manual/reference/mongodb-extended-json/ ) 中看到:

    • 在严格模式下,日期是一种 ISO-8601 日期格式,在模板 YYYY-MM-DDTHH:mm:ss.mmm<+ offset=""> 之后带有强制时区字段。

    • MongoDB JSON 解析器目前不支持加载表示 Unix 纪元之前的日期的 ISO-8601 字符串。在格式化前纪元日期和超过系统 time_t 类型可以容纳的日期时,使用以下格式: { "$date": { "$numberLong": "dateAsMilliseconds"} }

如果有人能解释一下为什么 MongoDB java 驱动程序、mongoexport 工具和官方文档之间没有使用通用格式,我将不胜感激?

谢谢。

最佳答案

显然 没有 Java 驱动程序偏离官方规范的充分理由。唯一的异常(exception)是那些不能用 ISO8601 格式表示的日期(如 B.C. 日期......)

作为解决方法,我扩展了 JsonWriter 类并提供了两个 toJson 静态方法作为如何使用它的示例:

package whatever.package.you.like;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import org.bson.BSONException;
import org.bson.BsonContextType;
import org.bson.BsonDocument;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.EncoderContext;
import org.bson.conversions.Bson;
import org.bson.json.JsonMode;
import org.bson.json.JsonWriter;
import org.bson.json.JsonWriterSettings;

import com.mongodb.MongoClient;

/**
 * A {@link JsonWriter} extension that conforms to the "strict" JSON format
 * specified by MongoDB for data/time values.
 * 
 * The {@link JsonWriter} class provided in the MongoDB Java driver (version
 * 3.2.2) does not conform to official MongoDB specification for strict mode
 * JSON (see https://docs.mongodb.com/manual/reference/mongodb-extended-json/).
 * This is specifically a problem with the date/time values which get filled
 * with a milliseconds value (i.e. {$date: 309249234098}) instead of the ISO8601
 * date/time (i.e. {$date: "2016-07-14T08:44:23.234Z"}) value which the
 * specification calls for. This extension of {@link JsonWriter} conforms to the
 * MongoDb specification in this regard.
 */
public class ConformingJsonWriter extends JsonWriter {
   private final JsonWriterSettings settings;

   private final Writer writer;

   private boolean writingIndentedDateTime = false;

   /**
    * Creates a new instance which uses {@code writer} to write JSON to.
    *
    * @param writer
    *           the writer to write JSON to.
    */
   public ConformingJsonWriter(final Writer writer) {
      this(writer, new JsonWriterSettings());
   }

   /**
    * Creates a new instance which uses {@code writer} to write JSON to and uses
    * the given settings.
    *
    * @param writer
    *           the writer to write JSON to.
    * @param settings
    *           the settings to apply to this writer.
    */
   public ConformingJsonWriter(final Writer writer,
         final JsonWriterSettings settings) {
      super(writer, settings);
      this.writer = writer;
      this.settings = settings;
      setContext(new Context(null, BsonContextType.TOP_LEVEL, ""));
   }

   private void writeIndentation(int skip) throws IOException {
      for (Context context = getContext()
            .getParentContext(); context != null; context = context
                  .getParentContext()) {
         if (skip-- <= 0) {
            writer.write(settings.getIndentCharacters());
         }
      }
   }

   private static String millisToIso8601(long millis) throws IOException {
      SimpleDateFormat dateFormat = new SimpleDateFormat(
            "yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'");
      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
      return dateFormat.format(new Date(millis));
   }

   @Override
   protected void doWriteDateTime(final long value) {
      if ((settings.getOutputMode() == JsonMode.STRICT)
            && (value >= -59014396800000L && value <= 253399536000000L)) {
         try {
            writeStartDocument();
            if (settings.isIndent()) {
               writingIndentedDateTime = true;
               writer.write(settings.getNewLineCharacters());
               writeIndentation(0);
            } else {
               writer.write(" ");
            }
            writer.write("\"$date\" : ");
            writer.write("\"");
            writer.write(millisToIso8601(value));
            writer.write("\"");
            writeEndDocument();
            writingIndentedDateTime = false;
         } catch (IOException e) {
            throw new BSONException("Wrapping IOException", e);
         }
      } else {
         super.doWriteDateTime(value);
      }
   }

   @Override
   protected void doWriteEndDocument() {
      if (writingIndentedDateTime) {
         try {
            writer.write(settings.getNewLineCharacters());
            writeIndentation(1);
            writer.write("}");
            if (getContext()
                  .getContextType() == BsonContextType.SCOPE_DOCUMENT) {
               setContext(getContext().getParentContext());
               writeEndDocument();
            } else {
               setContext(getContext().getParentContext());
            }
         } catch (IOException e) {
            throw new BSONException("Wrapping IOException", e);
         }
      } else {
         super.doWriteEndDocument();
      }
   }

   /**
    * Take a {@link Bson} instance and convert it to "strict" JSON
    * representation with no indentation (read, "NOT pretty printed").
    * 
    * @param bson
    *           The {@link Bson} instance to convert
    * @return The JSON representation.
    */
   public static String toJson(Bson bson) {
      return toJson(bson, new JsonWriterSettings());
   }

   /**
    * Take a {@link Bson} instance and convert it to JSON representation.
    * 
    * @param bson
    *           The {@link Bson} instance to convert
    * @param writerSettings
    *           {@link JsonWriterSettings} that specify details about how the
    *           JSON output should look.
    * @return The JSON representation.
    */
   public static String toJson(Bson bson,
         final JsonWriterSettings writerSettings) {
      BsonDocumentCodec encoder = new BsonDocumentCodec();
      ConformingJsonWriter writer = new ConformingJsonWriter(new StringWriter(),
            writerSettings);
      encoder.encode(writer,
            bson.toBsonDocument(BsonDocument.class,
                  MongoClient.getDefaultCodecRegistry()),
            EncoderContext.builder().isEncodingCollectibleDocument(true)
                  .build());
      return writer.getWriter().toString();
   }
}

关于json - 严格模式下的MongoDB日期格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38014515/

有关json - 严格模式下的MongoDB日期格式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  6. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  7. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  8. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

  9. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  10. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

随机推荐