Blog

Jongo, Abfrage in Java wie in der Mongo-Shell

Yves AMSELLEM

Yves AMSELLEM

Aktualisiert Oktober 22, 2025
6 Minuten

Mongo - die von 10gen unterstützte dokumentenorientierte NoSQL-Datenbank - bietet eine kompakte, leicht zu erlernende und gut dokumentierte Abfragesprache. Leider kann die Verwendung von Mongo mit seinem Java-Treiber knifflig sein: Abfragen, Mapping von Ergebnissen und der Umgang mit Polymorphismus erfordern viel Code. Einige Bibliotheken zielen darauf ab, dies zu vereinfachen(wie Morphia), aber keine erlaubt es, Abfragen in einer Shell-Form durchzuführen. Jongo versucht, diesen Bedarf zu decken, indem es Abfragen mit Hilfe von Strings durchführt und die Ergebnisse in Java-Objekte umwandelt (unmarshalling).

 Diesen Artikel auf französisch lesen

Mongo mit seiner Hülle

Mongo speichert seine Daten in BSON-Dokumenten, einem Attribut:Wert-Baum(Wert kann einfach, ein Array oder ein eingebettetes Objekt sein). Dokumente werden in Sammlungen gespeichert, Sammlungen in Datenbanken. Mongo ist schemalos, die Dokumente einer Sammlung müssen nicht die gleichen Attribute haben, sie können völlig unterschiedlich sein.

Die folgenden Befehle fügen zwei Dokumente in die Sammlung friends ein. Diese Sammlung wird automatisch erstellt, wenn sie nicht vorhanden ist.

[java gutter="false"] > db.friends.save({Name:'Joe', Alter:17, Adresse: {Stadt:'Paris', PLZ:75018}) > db.friends.save({Name:'Jack', Alter:19, Adresse: {Stadt:'New York', Straße:'22 Madison Ave'}) [/java]

Sobald die Sammlung erstellt ist, kann sie mit zahlreichen Operatoren abgefragt werden(größer als, nicht leer, usw.). Diese Abfragen können sich auf alle Attribute beziehen, sogar auf Unterknoten.

[java gutter="false"] > db.friends.find() [ {Name:'Joe', Alter:17, Adresse: {Stadt:'Paris', PLZ:75018}, {Name:'Jack', Alter:19, Adresse: {Stadt:'New York', Straße:'22 Madison Ave'} ] > db.friends.findEins({Alter: {$gt: 18> {Name:'Jack', Alter:19, Adresse: {Stadt:'New York', Straße:'22 Madison Ave'} > db.friends.find({'address.zip':{$exists:true}, 'address.city':'Paris'}) [ {Name:'Joe', Alter:17, Adresse: {Stadt:'Paris', Postleitzahl:75018} ] [/java]

In der Online-Dokumentation zu Mongo sind alle verfügbaren Operatoren aufgeführt. Dort wird auch erklärt, wie Sie Mongo in Sekundenschnelle installieren.

Mongo mit Jongo

Wir werden zwei Klassen, Friend und Address, verwenden, um Daten in Mongo in Java zu bearbeiten und zu speichern. Diese Klassen werden ohne Änderung vom Java-Treiber und von Jongo verwendet. Ihre Attribute sind privat; Konstruktoren mit Argumenten werden hier der Kürze halber nicht gezeigt.

[java] public class Friend { private String name; private int age; private Address address; Friend() {} // Konstruktor mit Attributen hier } public class Address { private String city; private Integer zip; private String street; Address() {} // Konstruktor mit Attributen hier } [/java]

Jongo greift über seinen Java-Treiber auf Mongo zu und stützt sich auf die für ihre Leistung bekannte Jackson Marshalling-Bibliothek, um die komfortable Mongo-Shell-Erfahrung in Java zu bieten. Der folgende Test initiiert eine Verbindung mit der xebia-Basis und dann mit der Friends-Sammlung; jedes Dokument dieser Sammlung wird nach jedem Test entfernt.

[java] public class JongoTest { MongoCollection collection; @Before public void setUp() throws Exception { Mongo mongo = new Mongo("127.0.0.1", 27017); DB db = mongo.getDB("xebia"); Jongo jongo = new Jongo(db); collection = jongo.getCollection("friends"); } @After public void tearDown() { collection.drop(); } } [/java]

Nach der Initialisierung ermöglicht die Klasse MongoCollection, die die Sammlung der Freunde darstellt, das direkte Speichern von Java-Objekten.

[java] public class JongoTest { @Before public void setUp() throws Exception { collection.save(new Friend("Joe", 17, new Address("Paris", 75000))); collection.save(new Friend("Jack", 19, new Address("New York", "22 Madison Ave"))); } @Test public void findAll() throws Exception { Iterable<Friend> friends = collection.find().as(Friend.class); assertThat(friends).hasSize(2); } } [/java]

Sobald die Dokumente erstellt sind - keine Überraschungen - sind die Anfragen die gleichen wie in der Shell. Dann definiert die as(Class)-Methode den Typ, in den die Ergebnisse umgewandelt werden müssen(die Klasse muss einen No-Args-Konstruktor haben - auch privat). Ergebnisattribute, die fehlen, werden auf Null gesetzt, Ergebnisattribute, die nicht im Objekt enthalten sind, werden ignoriert(auf diese Weise kann eine riesige Sammlung mit kleinen Objekten verwaltet werden).

Mit unseren vorherigen Anfragen ergibt sich folgendes.

[java] public class JongoTest { @Test public void findOver18() throws Exception { Friend jack = collection.findOne("{Alter: {$gt: 18}}").as(Friend.class); assertThat(jack.getName()).isEqualTo("Jack"); assertThat(jack.getAddress().getZip()).isNull(); assertThat(jack.getAddress().getStreet()).isEqualTo("22 Madison Ave"); // [...] andere Behauptungen } @Test public void findInParis18() throws Exception { Iterierbar<Freund> Freunde = collection.find("{'adresse.zip':{$exists:true},'adresse.stadt':'Paris'}") .as(Friend.class); Freund joe = friends.iterator().next(); assertThat(joe.getName()).isEqualTo("Joe"); assertThat(joe.getAddress().getZip()).isEqualTo(75000); assertThat(joe.getAddress().getStreet()).isNull(); assertThat(friends.iterator().hasNext()).isFalse(); // [...] andere Behauptungen } } [/java]

Jongo bietet die überwiegende Mehrheit der Mongo-Operationen - Speichern, Aktualisieren, Einfügen, Entfernen, Zählen, Sortieren, Unterscheiden - und versucht bei jeder dieser Operationen, dem Geist der Mongo-Shell so getreu wie möglich zu sein. Die folgenden Tests geben einen Einblick.

[java] public class JongoTest { @Test public void sort() throws Exception { Iterierbar<Freund> friends = collection.find().sort("{Name: -1}").as(Friend.class); assertThat(friends).onProperty("name").containsExactly("Joe", "Jack"); } @Test public void distinct() { Liste<Adresse> addresses = collection.distinct("address").as(Address.class); assertThat(addresses).onProperty("city").contains("Paris", "New York"); } @Test public void count() { long count = collection.count("{Name: 'Joe'}"); assertThat(count).isEqualTo(1); } @Test public void crud() { Friend joe = collection.findOne("{Name: 'Joe'}").as(Friend.class); assertThat(joe.getAge()).isEqualTo(17); collection.update("{Name: 'Joe'}").with("{$inc: {Alter: 1}}"); joe = collection.findOne("{Name: 'Joe'}").as(Friend.class); assertThat(joe.getAge()).isEqualTo(18); collection.remove("{Name: 'Joe'}"); joe = collection.findOne("{Name: 'Joe'}").as(Friend.class); assertThat(joe).isNull(); } } [/java]

Jongo ist im zentralen Maven-Repository verfügbar.

[java] <Abhängigkeit> <groupId>org.jongo</groupId> <artifactId>jongo</artifactId> <Version>0.1</version> </dependency> [/java]

Mongo mit seinem Java-Treiber

Die beste Art und Weise, die Gründe für Mongo zu erläutern, ist, es nicht zu verwenden. Sehen wir uns an, wie Sie Mongo direkt mit seinem Java-Treiber verwenden können.

[java] public class MongoJavaDriverTest { DBCollection friends; @Before public void setUp() throws Exception { Mongo mongo = new Mongo("127.0.0.1", 27017); friends = mongo.getDB("xebia").getCollection("friends"); } @After public void tearDown() { friends.drop(); } } [/java]

Der Treiber bietet keine Möglichkeit, Java-Objekte zu speichern; er benötigt eine Struktur von BasicDBObject.

[java] public class MongoJavaDriverTest { @Vor public void setUp() throws Exception { friends.save(newBasicDBObject("Joe", "Paris", ...)); friends.save(newBasicDBObject("Jack", "New York", ...)); } private BasicDBObject newBasicDBObject(String name, String city, ...) { BasicDBObject obj = new BasicDBObject(); obj.put("name", name); obj.put("Adresse", new BasicDBObject("Stadt", city)); // [...] sollte jedes Feld anpassen return obj; } @Test public void findAll() throws Exception { DBCursor find = friends.find(); assertThat(find.size()).isEqualTo(2); } } [/java]

Die Ergebnisse des Treibers sind ebenfalls BasicDBObject. Daher ist es notwendig, jedes Feld an das entsprechende Java-Attribut anzupassen.

[java] public class MongoJavaDriverTest { @Test public void findOver18() throws Exception { DBObject findOne = friends.findOne( QueryBuilder.start("Alter").greaterThan(18).get() ); Friend jack = adaptDBObjectToFriend(findOne); assertThat(jack.getName()).isEqualTo("Jack"); // [...] jedes Feld testen } private Friend adaptDBObjectToFriend(DBObject dbFriend) { String name = (String) dbFriend.get("name"); DBObject dbAddress = (DBObject) dbFriend.get("address"); Adresse Adresse = new Adresse((String) dbAddress.get("Stadt"), ...); // [...] sollte jedes Feld anpassen return new Friend(Name, Alter, Adresse); } } [/java]

Schließlich müssen, wie im vorherigen Beispiel gezeigt, auch die Anfragen angepasst werden. Die beiden anfänglichen Anfragen, die so kurz sind, müssen mit einem QueryBuilder(oder unter Verwendung einer BasicBBObject-Struktur) neu geschrieben werden und verlieren dadurch ihre Benutzerfreundlichkeit.

[java] public class MongoJavaDriverTest { @Test public void findInParis18() throws Exception { DBCursor find = friends.find( QueryBuilder.start("adresse.zip").exists(true) .and("adresse.city").is("Paris").get() ); assertThat(find.size()).isEqualTo(1); Friend joe = adaptDBObjectToFriend(find.next()); assertThat(joe.getName()).isEqualTo("Joe"); // [...] jedes Feld testen } } [/java]

Epilog: Schließen Sie sich Jongo an

In der Online-Dokumentation von Jongo werden alle Operatoren vorgestellt, insbesondere die Art und Weise, wie Polymorphismus, Bezeichner und Anfrageparameter behandelt werden. Jongo ist ein Open-Source-Projekt, das auf GitHub gehostet wird und unter der Apache 2.0-Lizenz steht. Die Mailing-Liste ist der beste Ort, um ein Problem zu melden oder eine neue Funktionalität vorzuschlagen. Pull Requests sind willkommen, ebenso wie neue Committer.

Nach der Einladung zur Paris Mongo User Group und zur MongoDB Paris 2012 wird Jongo bei der nächsten Paris Java User Group am 3. Juli 2012 dabei sein.

Die Version 0.2 wird in ein paar Tagen erscheinen. Sie wird vor allem Unterstützung für das brandneue Aggregations-Framework bieten, das mit der zukünftigen Version Mongo 2.2 kommen wird.

Verfasst von

Yves AMSELLEM

Contact

Let’s discuss how we can support your journey.