2014-03-30 3 views
1

У меня есть коллекция в MongoDB со сложной структурой и вложенными документами. документ имеет структуру, как это:MongoDB найти поддокумент и отсортировать результаты

doc1 = { 
    '_id': '12345678', 
    'url': "http//myurl/...", 
    'nlp':{ 
     "status": "OK", 
     "entities": { 
      "0": { 
       "type" : "Person", 
       "relevance": "0.877245", 
       "text" : "Neelie Kroes" 
      }, 
      "1": { 
       "type": "Company", 
       "relevance": "0.36242", 
       "text": "ICANN" 
      }, 
      "2": { 
       "type": "Company", 
       "relevance": "0.265175", 
       "text": "IANA" 
      } 
     } 
    } 
} 


doc2 = { 
    '_id': '987456321', 
    'url': "http//myurl2/...", 
    'nlp':{ 
     "status": "OK", 
     "entities": { 
      "0": { 
       "type": "Company", 
       "relevance": "0.96", 
       "text": "ICANN" 
      }, 
      "1": { 
       "type" : "Person", 
       "relevance": "0.36242", 
       "text" : "Neelie Kroes" 
      }, 
      "2": { 
       "type": "Company", 
       "relevance": "0.265175", 
       "text": "IANA" 
      } 
     } 
    } 
} 

Моя задача состоит в том, чтобы искать «типа» И «текст» внутри поддокументе, то сортировать по «значимости». С оператором $ elemMatch Я в состоянии выполнить запрос:

db.resource.find({ 
    'nlp.entities': { 
     '$elemMatch': {'text': 'Neelie Kroes', 'type': 'Person'} 
    } 
}); 

совершена, теперь я должен сортировать все записи с организациями типа «Person» и значение «Нила Kroes» по релевантности по убыванию.

Я пробовал с обычным «сортировкой», но, как manual said о sort() в $ elemMatch, результат может не отражать порядок сортировки, потому что sort() применялся к элементам массива до $ elemMatch проекция.

Фактически, _id: 987456321 будет первым (с релевантностью 0,96, но ссылка на ICANN).

Как это сделать, чтобы отсортировать документы, сопоставив релевантность поддокумента?

P.S .: Я не могу изменить структуру документа.

+0

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

ответ

1

Как уже отмечалось, я надеюсь, что у ваших документов действительно есть массив, но если $ elemMatch работает на вас, тогда они должны.

Во всяком случае, вы не можете сортировать по элементу массива с помощью find. Но есть случай, когда вы можете сделать это с помощью .aggregate():

db.collection.aggregate([ 

    // Match the documents that you want, containing the array 
    { "$match": { 
     "nlp.entities": { 
      "$elemMatch": { 
       "text": "Neelie Kroes", 
       "type": "Person" 
      } 
     } 
    }}, 

    // Project to "store" the whole document for later, duplicating the array 
    { "$project": { 
     "_id": { 
      "_id": "$_id", 
      "url": "$url", 
      "nlp": "$nlp"   
     }, 
     "entities": "$nlp.entities" 
    }}, 

    // Unwind the array to de-normalize 
    { "$unwind": "$entities" }, 

    // Match "only" the relevant entities 
    { "$match": { 
     "entities.text": "Neelie Kroes", 
     "entities.type": "Person" 
    }}, 

    // Sort on the relevance 
    { "$sort": { "entities.relevance": -1 } }, 

    // Restore the original document form 
    { "$project": { 
     "_id": "$_id._id", 
     "url": "$_id.url", 
     "nlp": "$_id.nlp" 
    }} 
]) 

Так по существу, после выполнения условия $match для документов, содержащих соответствующий матч, вы затем использовать $project «магазин» исходный документ в _id поле и $unwind - «копия» массива «сущностей».

Следующий $match «фильтрует» содержимое массива только для тех, которые актуальны. Затем вы применяете $sort к «согласованным» документам.

Поскольку «оригинальный» документ хранился под номером _id, вы используете $project для «восстановления» структуры, с которой документ должен был начаться.

Вот как вы «сортируете» свой согласованный элемент массива.

Обратите внимание, что если вы имели несколько «спичку» в массиве для родительского документа, то вам придется использовать дополнительную $group сцену, чтобы получить значение $ макс для поля «актуальности» для того, чтобы завершить Сортировать.

+0

Спасибо, что он отлично работает. В первый раз это медленно, но после очень быстро. Является ли агрегатная функция хранимой в ОЗУ, кеше или другой системе ускорения? Еще раз спасибо. –

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