【问题标题】:Excluding $fields When Retrieving Document from MongoDB从 MongoDB 检索文档时排除 $fields
【发布时间】:2016-09-20 20:28:05
【问题描述】:

有没有办法按原样从 MongoDB 获取文档,而不是将某些字段转换为包含 $ 字段的对象?

例如,我有一个名为 timestamp 的字段,我在其中存储了一个 long 值。它过去只返回一个值,然后突然在大约一周后开始返回一个对象:

{
    "$numberLong": "1474402633708"
}

这与嵌套对象的 _id 字段相同。它正在返回“_id”,并在某些时候切换为返回一个带有 $oid 的对象,例如顶层。我真的需要它至少保持一致。

这是来自 MongoDB 客户端的屏幕截图。第一个序列化为 JSON 时不返回 $numberLong 而最后一个返回。

这只是某处的配置吗?这完全没有意义。

这里是从控制台消除任何关于时间戳字段的数据不同的疑问。

> db["page"].find()
{ "_id" : ObjectId("57dd99ab390a777a9720e8c2"), "entries" : [ { "widget" : { "_id" : ObjectId("57dec085390a777a9720e8c5"), "_db" : "system-s", "_col" : "card" }, "width" : -1, "height" : -1 }, { "widget" : { "_id" : ObjectId("57df6119390a778641f4fd25"), "_db" : "system-s", "_col" : "card" }, "width" : -1, "height" : -1 } ], "title" : "Simple 2", "timestamp" : 1474257177398 }
{ "_id" : ObjectId("57e171ff303c2807d6ea1dd6"), "entries" : [ { "widget" : { "_id" : ObjectId("57e1720b303c2807d6ea1dd9"), "_db" : "system-s", "_col" : "card" }, "width" : -1, "height" : -1 } ], "title" : "Test 2", "timestamp" : 1474392587984 }

我目前正在使用 MongoDB Java lib v3.3.0 对其进行测试。这是代码以防万一。

//the endpoint is exposed using Spark
get("/db/:collection/get/:id", (request, response) -> {
    String collectionName = request.params(":collection");
    String id = request.params(":id");

    Document doc = getDocument(collectionName, id);
    return doc.toJson(); //this is where I see the issues
});

public Document getDocument(String collectionName, String id){
    MongoCollection<Document> coll = db.getCollection(collectionName);

    BasicDBObject query = new BasicDBObject();
    query.put("_id", new ObjectId(id));
    FindIterable<Document> itr = coll.find(query);
    Document doc = itr.first();
    if(doc != null){
        return doc;
    }

    return null;
}

这是 Javascript 中的一种解决方法,可确保数据一致,以防您也遇到此问题。这段代码使用了一些 jQuery 函数,但是如果你不使用 jQuery,你可以替换它们。

function scrub(obj){
    if(obj.$oid){
        return obj.$oid;
    }else if(obj.$numberLong){
        return parseInt(obj.$numberLong);
    }else if(obj.$numberInt){
        return parseInt(obj.$numberInt);
    }else if(obj.$date){
        if($.isPlainObject(obj.$date) && obj.$date.$numberLong){
            return parseInt(obj.$date.$numberLong);
        }else{
            return parseInt(obj.$date);
        }
    }else{
        $.each(obj, function(k, v){
            if($.isPlainObject(v)){
                obj[k] = scrub(v);
            }else if($.isArray(v)){
                $.each(v, function(kk, vv){
                    if($.isPlainObject(vv)){
                        v[kk] = scrub(vv);
                    }
                });
            }
        });
    }

    return obj;
};

更新 1:

在逐行调试之后,我发现对于 long 值以某种方式被解释为 double (指数值)的情况,然后我得到了预期值,而那个值被解释为 long (int64),我因为默认模式是 STRICT,所以要返回 $numberLong。现在的问题是如何将 long 值存储为 double 和 long 。

【问题讨论】:

  • 是在您的应用程序中使用驱动程序还是在 Mongo shell 中发生?
  • 使用 MongoDB Java 客户端时会发生这种情况。
  • 更具体地说,我在 toJson 方法调用的返回值中看到了这一点。

标签: java mongodb object numbers


【解决方案1】:

您使用哪个客户端访问您的 mongoDB?

您的客户似乎以错误的格式显示数据。如果您更喜欢 gui 客户端,可以使用 mongo shell 或 robomongo 进行检查。

【讨论】:

  • 至少时间戳字段的数据显示不正确。您可以在上面看到 mongo shell 输出。它们完全相同。除非你说 mongo shell 也不正确。
  • Shell 不正确。但是mongo shell和java驱动还是有一些差距的,我亲身体验过。
  • 我添加了对问题的更新。只要没有 $numberLong 就被序列化的那个会以某种方式存储为双精度。
【解决方案2】:

我发现了问题。 Mongo 客户端 (http://www.mongoclient.com) 将 long 值保存为 double。我的代码突然中断的原因是因为我试图使用该工具删除损坏的数据,然后将 long 值保存为 double 值。这导致它变得不一致。我最初没有意识到这一点,因为我不知道修改一个文档实际上会导致结果集中的每个文档也被再次保存,否则我会更早地发现这一点。

并回答主题中的问题。您不能排除 $fields。序列化工作如下:

32 int -> always value
64 int -> STRICT uses $numberLong, CONSOLE uses NumberLong(d), UNKNOWN uses value
double -> always value

没有办法将模式设置为 null 并使其工作,因为对象 ID 的序列化将引发未知模式的异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 2017-01-11
    • 1970-01-01
    • 2015-10-01
    相关资源
    最近更新 更多