2016-10-12 2 views
1

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

{ 
    "_id" : ObjectId("57f95e8e385bb61c5cf2cd18"), 
    //some other fields 
    "messages" : [ 
      { 
        "sender" : "57ec1aaa0ffe16123439d52b", 
        "message" : "Hello!", 
        "sentTime" : "Oct 13, 2016 1:51:31 AM" 
      }, 
      { 
        "sender" : "57ec1aaa0ffe16123439d52b", 
        "message" : "Hello!", 
        "sentTime" : "Oct 13, 2016 1:51:33 AM" 
      } 
    ] 
} 

Я хочу найти свою коллекцию на основе _id поля и только получить данные из messages sub-document в качестве результата запроса с использованием java-драйвера для MongoDB, поскольку я хочу, чтобы Map to POJO-массив использовал Gson.

Желаемая Выход:

[ 
     { 
       "sender" : "57ec1aaa0ffe16123439d52b", 
       "message" : "Hello!", 
       "sentTime" : "Oct 13, 2016 1:51:31 AM" 
     }, 
     { 
       "sender" : "57ec1aaa0ffe16123439d52b", 
       "message" : "Hello!", 
       "sentTime" : "Oct 13, 2016 1:51:33 AM" 
     } 
] 

Как я могу идти с этим с помощью драйвера Java для MongoDB

ответ

0

Нам нужно указать запрос и список полей, вот пример того, как сделать это:

DB db = //get db 

DBObject object = new BasicDBObject(); 
object.put("_id", new ObjectId("<some id>")); 
DBObject fields = new BasicDBObject(); 
fields.put("messages", 1); 
DBObject result = db.getCollection("test").findOne(object, fields); 
System.out.println(result.get("messages")); 
+0

Это не сработает. Он дает документ с полем поля id и сообщений в нем. Результат такой же, как и первый json, заданный в вопросе, за исключением всех остальных полей. Но мне нужно, чтобы это был только массив вспомогательных документов, как во втором json, который я поставил под вопрос. Спасибо – kritya

+0

Невозможно получить только часть вспомогательного документа. Мы можем указать поля типа 'messages.sender', но не можем напрямую получить эту часть. Кроме того, вы не можете указывать поля include и exclude одновременно, и мы все равно вернем идентификатор. Так что это как можно ближе. –

+0

Тогда возможно ли, что я могу сортировать массив сообщений на основе let say sentTime? – kritya

0

Возможно, это немного уродливо, но это сработает.

chats.aggregate(Arrays.asList(
    match(eq("_id", <your id here>)), 
    unwind("$messages"), 
    project(fields(excludeId(), 
        computed("sender", "$messages.sender"), 
        computed("message", "$messages.message"), 
        computed("sentTime", "$messages.sentTime"))) 
    )).forEach(printBlock); 

printBlock только распечатывает каждый документ (их можно собрать, чтобы массировать там).

Block<Document> printBlock = new Block<Document>() { 
     @Override 
     public void apply(final Document document) { 
      System.out.println(document.toJson()); 
     } 
    }; 
+0

Я считаю, что я не могу это сделать. Извините, но я не использовал структуру агрегатов. Не могу ли я вернуть полный объект? Кроме того, как производительность агрегирования по сравнению с поиском для того же? – kritya

+0

Метод aggregate вернет вам объект AggregateIterable , он имеет обычный метод итерации, который можно использовать вместо forEach. Что касается производительности, вы будете соответствовать только одному документу на самом первом этапе агрегации, и только этот один документ пойдет вниз по конвейеру агрегации. Таким образом, в этом конкретном случае это не должно быть большой проблемой. –

+0

Что мы делаем, так это. Во-первых, мы выбираем один объект, используя «match», этот единственный объект переходит к конвейеру агрегации, чем мы «разматываем» сообщения - это означает, что каждое сообщение из нашего массива сообщений будет помещено в отдельный документ на выходе (из официального doc: «Этап сценария $ unwind деконструирует поле массива из входных документов для вывода документа для каждого элемента»). И чем из этого полученного документа мы берем только поля сообщений и сопоставляем их с желаемыми именами, используя «проект». –

Смежные вопросы