JSON.parse() equivalent in mongo driver 3.x for Java
Asked Answered
B

6

14

JSON.parse() from mongo (Java driver) returns either a BasicDBList or a BasicDBObject.

However, when migrating to mongo driver 3.x, what's the new parse method that returns either Document or List<Document>?

In the new driver, Document.parse() only parses an object, not an array (throws an exception when given an array).

What is the equivalent of JSON.parse() for Arrays with 3.x Java drivers ?

Broussard answered 23/12, 2015 at 13:38 Comment(1)
I am facing the same issue, did you get any clean solution to this?Regime
E
13

A simple trick to parse any JSON and to get either Document or List<Document>:

Document.parse("{\"json\":" + json + "}").get("json")
Eyrir answered 31/1, 2018 at 17:30 Comment(0)
C
4

To parse JSON string data using the mongodb java driver 3.x:

Parse JSON document:

Use the Document.parse() static method to parse a single JSON document.

Document doc = Document.parse("{\"objA\":{\"foo\":1}}");

Parse JSON array:

Use an instance of BsonArrayCodec to decode a JsonReader.

For example:

final String JSON_DATA
    = "[{\"objA\":{\"foo\":1}},"
    + "{\"objB\":{\"bar\":2}}]";

final CodecRegistry codecRegistry = CodecRegistries.fromProviders(asList(new ValueCodecProvider(),
    new BsonValueCodecProvider(),
    new DocumentCodecProvider()));

JsonReader reader = new JsonReader(JSON_DATA);
BsonArrayCodec arrayReader = new BsonArrayCodec(codecRegistry);

BsonArray docArray = arrayReader.decode(reader, DecoderContext.builder().build());

for (BsonValue doc : docArray.getValues()) {
    System.out.println(doc);
}

ref: http://api.mongodb.org/java/3.2/org/bson/json/JsonReader.html, http://api.mongodb.org/java/3.2/org/bson/codecs/BsonArrayCodec.html

Corwun answered 15/2, 2016 at 0:24 Comment(1)
Why not to just use BsonArray.parse then?Laminous
H
1

Added cast to @Oleg Nitz answer, for completeness.

Object object = Document.parse("{\"json\":" + jsonData.getJson() + "}").get("json");

if (object instanceof ArrayList) {
    documents = (ArrayList<Document>) object;
} else (object instanceof Document) {
    document = (Document) object;
}
Housebreaking answered 14/1, 2019 at 11:34 Comment(0)
E
0

How about this:

Document doc = new Document("array", JSON.parse("[ 100, 500, 300, 200, 400 ]", new JSONCallback()));
System.out.println(doc.toJson()); //prints { "array" : [100, 500, 300, 200, 400] }
Elwood answered 7/1, 2016 at 14:28 Comment(5)
If you do a doc.get("array"), it'll return a BasicDBList, instead of a List :(Broussard
True, but it is subclass of ArrayList. So you could do this: new Document("array", new ArrayList((List)JSON.parse("[ 100, 500, 300, 200, 400 ]", new JSONCallback()))); or use toMap(): BasicDBList bDBl1 = (BasicDBList) JSON.parse("[ 100, 500, 300, 200, 400 ]", new JSONCallback()); new Document("array", bDBl1.toMap());Elwood
It is possible we are missing something as this is not very cleanElwood
That wouldn't work either because, if my array consisted of documents, it would be parsed as BasicDBObject, and not a Document.Broussard
I agree, we're missing something crucial here.Broussard
T
0

You're right that there's no easy equivalent.

If you use line-delimited JSON documents instead of a JSON array, it becomes fairly straightforward:

List<Document> getDocumentsFromLineDelimitedJson(final String lineDelimitedJson) {
    BufferedReader stringReader = new BufferedReader(
          new StringReader(lineDelimitedJson));
    List<Document> documents = new ArrayList<>();
    String json;
    try {
        while ((json = stringReader.readLine()) != null) {
            documents.add(Document.parse(json));
        }
    } catch (IOException e) {
        // ignore, can't happen with a StringReader
    }
    return documents;
}

For example, this call

System.out.println(getDocumentsFromLineDelimitedJson("{a : 1}\n{a : 2}\n{a : 3}"));

will print:

[Document{{a=1}}, Document{{a=2}}, Document{{a=3}}]

Tombouctou answered 7/1, 2016 at 21:10 Comment(3)
This is rarely the case though, isn't it?Broussard
It depends. This is the format output by mongoexport by default, for example. And there are several standardization efforts: JSON lines and ndjsonTombouctou
I was referring to line separated JSON. Mostly, you've got objects in an array, which is the value to another key in another object altogether.Broussard
H
0

The easiest equivalent for me is to use any json library to convert the json to POJO. Below is an example using jackson:

String input = "[{\"objA\":{\"foo\":1}},{\"objB\":{\"bar\":2}}]";
ObjectMapper mapper = new ObjectMapper();
List<Document> output = (List<Document>) mapper.readValue(input, List.class)
            .stream().map(listItem -> new Document((LinkedHashMap)listItem))
            .collect(Collectors.toList());
Hoisch answered 13/2, 2018 at 13:15 Comment(1)
This doesn't handle nested objects, a map inside of your top level map.Mousey

© 2022 - 2024 — McMap. All rights reserved.