问题
Is there a way to get the document from MongoDB as is rather than having some fields converted to object containing $ fields?
For example, I have a field called timestamp where I store a long value. It used to return just a value and all the sudden it starts returning an object after about a week:
{
"$numberLong": "1474402633708"
}
This is the same with _id field for a nested object. It was returning "_id" and at some point switched to return an object with $oid like for the top level. I really need it to at least be consistent.
Here's the screenshot from MongoDB Client. The first one when serialized to JSON doesn't return $numberLong while the last one does.
Is this just a configuration somewhere? It makes absolutely no sense.
And here's from the console to remove any doubt that the data for the timestamp field is different.
> 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 }
I'm currently testing it with MongoDB Java lib v3.3.0. Here's the code just in case it helps.
//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;
}
Here's a workaround in Javascript to make sure data is consistent in case you run into this issue as well. This code uses some jQuery functions, but you can replace them if you don't use 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;
};
Update 1:
After debugging line-by-line, I found that for the case where long value back is somehow interpreted as double (exponential value), then I'm getting expected value back while the one interpreted as long (int64), I'm getting back $numberLong since the default mode is STRICT. Now the question is down to how did a long value sometime get stored as double and sometime as long.
回答1:
Which client are you using to access your mongoDB ?
Seems like your client is displaying the data in wrong format. You can check this with mongo shell or robomongo if you prefer gui client.
回答2:
I found the issue. It's the Mongo Client (http://www.mongoclient.com) that's saving the long value as double. The reason that my code suddenly break was because I was trying to remove corrupted data using the tool and the long value was then saved as double value. This caused it to become inconsistent. I didn't initially realize this since I didn't know that modifying one document actually causes every documents in the result sets to also be saved again or I would have figured this out much earlier.
And to answer the question in the subject. You can't exclude the $fields. The serialization works as follow:
32 int -> always value
64 int -> STRICT uses $numberLong, CONSOLE uses NumberLong(d), UNKNOWN uses value
double -> always value
There is no way to set the mode to null and get it to work since serialization of object ID will throw an exception for unknown mode.
来源:https://stackoverflow.com/questions/39603179/excluding-fields-when-retrieving-document-from-mongodb