Получить вложенный документ в массиве как DBObject(S)

Я очень новичок в MongoDB, и я использую его вместе с драйвером Java. У меня есть такая структура документа:

{ "_id" : ObjectId("4f7d2ba6fd5a306d82687d48"), "room" : "Den" }
{ "_id" : ObjectId("4f7d2baafd5a306d82687d49"), "room" : "Foyer" }
{ "_id" : ObjectId("4f7d2fdcfd5a306d82687d4a"), "room" : "Master Bedroom" }
{ "_id" : ObjectId("4f7d301afd5a306d82687d4b"), "room" : "Guest Bedroom" }
{ "_id" : ObjectId("4f7d2b98fd5a306d82687d47"), "code" : "A", "lights" : [ { "name" : "Overhead", "code" : "1" } ], "room" : "Kitchen" }

где последняя строка представляет особый интерес для иллюстрации того, что я хочу сделать. Каждый документ-это комната и может иметь ключ "огни", соответствующий значению, которое является массивом вложенных документов. С точки зрения моделирования у меня есть дом, в котором есть 0-n комнат, в каждой из которых есть 0-n огней. Что я хочу сделать на Java, это взять название комнаты как параметр и возвращает коллекцию DBObject, соответствующую вложенным документам в массиве lights - "get me all lights for room 'kitchen'", например.

до сих пор, продолжая постепенно в стиле TDD, я построил этот запрос:

public static final String ROOM_KEY = "room";

public static final String EQUALS_KEY = "$eq";

private BasicDBObject buildRoomNameQuery(String roomName) {

    BasicDBObject myQuery = new BasicDBObject();
    myQuery.put(ROOM_KEY, new BasicDBObject(EQUALS_KEY, roomName));

    return myQuery;
}

Я понимаю, что это даст мне весь документ комнаты для имени комнаты, которую я передаю. Я немного застрял на том, что лучший способ начать отсюда-получить то, что я хочу. Возможно ли то, что я делаю, с помощью простой запрос, или мне придется получить массив и перебирать его в коде, отбрасывая элементы как DBObject? Я также открыт для предложений по лучшей структуре документов для моей цели - я никоим образом не женат на этой структуре.

для немного перспективы, я довольно хорошо разбираюсь в SQL и традиционных реляционных базах данных, если это помогает с точки зрения объяснительных аналогий. Кроме того, если я убиваю терминологию MongoDB, пожалуйста, поправьте меня. Спасибо продвижение.

4 ответов


Итак, вы можете сделать что-то вроде этого:

DBCollection coll = db.getCollection("test");
BasicDBObject query = new BasicDBObject("room", "Kitchen"); 

// optional, limit the fields to only have the lights field
BasicDBObject fields = new BasicDBObject("lights",1).append("_id",false);
DBCursor curs = coll.find(query, fields);
while(curs.hasNext()) {
  DBObject o = curs.next();

  // shows the whole result document
  System.out.println(o.toString());
  BasicDBList lights = (BasicDBList) o.get("lights");

  // shows the lights array -- this is actually a collection of DBObjects
  System.out.println(lights.toString());

  // optional: break it into a native java array
  BasicDBObject[] lightArr = lights.toArray(new BasicDBObject[0]);
  for(BasicDBObject dbObj : lightArr) {
    // shows each item from the lights array
    System.out.println(dbObj);
  }
}

кроме того, я рекомендую использовать QueryBuilder в драйвере Java-это немного более лаконично, чем создание запросов из DBObjects. Еще лучше, проверьте Morphia, который является сопоставителем объектов, который использует драйвер Java. Он изначально поддерживает модели сущностей, в которых есть списки, и сериализует/десериализует их в Mongo без необходимости иметь дело с материалом DBObject.


посмотрите на пакет spring mongo. Действительно хороший способ работы с mongo с помощью POJO documents

http://www.springsource.org/spring-data/mongodb

вам не нужно будет выполнять кастинг и работать со строками


вы можете использовать итератор для полей

Iterator<DBObject> fields = curs.iterator();
          while(fields.hasNext()){
              DBObject field = (DBObject) fields.next().get("lights");
              System.out.println(field.get("name"));
            }  

для более новых версий рассмотрите использование Document. Чтобы избежать непроверенных приведений и предупреждений линтера, наряду с написанием собственного цикла, используйте get(final Object key, final Class<T> clazz) способ:

List<Document> comments = posts.get("comments", docClazz)

здесь docClazz - это то, что вы создаете один раз:

final static Class<? extends List> docClazz = new ArrayList<Document().getClass();