2017-05-19 44 views
1

docs注:

要在$匹配階段使用$文本中,$匹配階段必須是第一階段管道。

一些示例JSON:

{"pid":"b00l16vp", "title": "in our time","categories":{"category1":["factual", "arts culture and the media", "history"]}} 
{"pid":"b0079mpp", "title": "doctor who", "categories":{"category2":["childrens", "entertainment and comedy", "animation"],"category1":["signed"]}} 
{「pid":"b00htbn3"} 
{「pid":"b00gdhqw","categories":{"category2":["factual"],"category3":["scotland"],"category4":["lifestyle and leisure", "food and drink"],"category1":["entertainment", "games and quizzes"]}} 

我有以下查詢:

List<BasicDBObject> pipeline = new ArrayList<>() 
      BasicDBObject criteria = new BasicDBObject() 
      BasicDBObject theProjections = new BasicDBObject() 
      AggregateIterable iterable 

    //value is coming from a parameter 
     if (value != null) { 
    //a text index has been created on the title field 
      criteria.put('$text', new BasicDBObject('$search', value)) 

     } 
//cats is coming from a parameter but it will be an array of Strings 
if (cats.length != 0) { 

      ArrayList<BasicDBObject> orList = new ArrayList<>() 
      ArrayList<BasicDBObject> andList = new ArrayList<>() 
      BasicDBList theMegaArray = new BasicDBList() 


      for (int i = 1; i <= 5; i++) { 

       String identifier = "categories.category" + i 
       String cleanIdentifier = '$' + identifier 
       //If the category does not exist, put in a blank category 
       theMegaArray.add(new BasicDBObject('$ifNull', Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST))) 
      } 
//merges all of the category arrays into 1 
      theProjections.put("allCategories", new BasicDBObject('$setUnion', theMegaArray)) 
      orList.add(new BasicDBObject("allCategories", new BasicDBObject('$all', cats))) 

      andList.add(new BasicDBObject('$or', orList)) 
      criteria.put('$and', andList) 
     } 
    pipeline.add(new BasicDBObject('$project', theProjections)) 
    pipeline.add(new BasicDBObject('$match', criteria)) 


    //and by default 
    iterable = collection.aggregate(pipeline) 

的問題是,如果我想在貓搜索,我需要的投影是在管道第一但如果我想要文字,那麼我需要比賽首先在那裏。我有兩種方法可以做到嗎?

+0

您不能像聚合管道的第一階段那樣運行「文本搜索」。造成這種情況的原因很簡單,因爲您需要索引,並且在第一階段之後的任何事情「可以」改變文檔的結構,並因此使索引的使用無效。 –

+0

我在那裏看到'$ setUnion'。你知道你可以在這些數組的所有可能的字段名稱上指定文本索引。根據本質進行的文本搜索適用於所有要指定的字段,因此不需要聚合管道將它們合併。 –

+0

我希望cats數組完全匹配類別對象中的內容。我相信,即使只匹配1個詞@NeilLunn,文本搜索也會帶來結果 – kulsoompatel

回答

1

這是一個非常簡單的解決方案。

我創建了一個新的標準對象

BasicDBObject criteriaCat = new BasicDBObject() 

添加的類別,以它來代替原來的標準。

criteriaCat.put('$and', andList) 

把$匹配放在管道中,然後是$項目,如果有貓在結果上再次運行$匹配。

pipeline.add(new BasicDBObject('$match', criteria)) 
     pipeline.add(new BasicDBObject('$project', theProjections)) 

     if (cats.length != 0) { 
      pipeline.add(new BasicDBObject('$match', criteriaCat)) 
     } 
     pipeline.add(new BasicDBObject('$sort', sorting)) 

     //and by default 
     iterable = collection.aggregate(pipeline) 
相關問題