2017-05-18 16 views
0

나는 다음과 같은 JSON이 있습니다는 MongoDB의 자바 드라이버를 사용하여 쿼리에 대해 여러 배열을 결합

{"pid":"b00l16vp","categories":{"category1":["factual", "arts culture and the media", "history"]}} 
{"pid":"b0079mpp","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"]}} 

내 의도는 범주가 하나의 배열의 배열을 모두 결합하여 문자열의 배열을 사용하여 객체를 조회하는 것입니다. 나는 다음과 같은 코드를 가지고 : 나는 지금까지이 코드를 작성하는 올 this 질문을 사용했다

String [] cats = ["childrens", "signed"] 
BasicDBObject theProjections = new BasicDBObject() 
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 
    def temp = [cleanIdentifier, []] 
    theMegaArray.add(new BasicDBObject('$ifNull', temp)) 
} 
//The megaArray is the array created in the above loop which combines all arrays 
BasicDBObject theData = new BasicDBObject('$setUnion', theMegaArray) 
BasicDBObject theFilter = new BasicDBObject('input', theData) 
theFilter.put("as", "megaArray") 
//all of the values found in cats should match the megaArray 
theFilter.put("cond", new BasicDBObject('$all', ["\$\$megaArray", cats])) 
theProjections.put('$filter', theFilter) 
FindIterable iterable = collection.find(criteria).projection(theProjections) 

합니다. $setUnion에는 모든 필드가 JSON에 표시 될 것으로 예상되므로 여러 가지 categrories 배열이 있으므로 $ifNull을 사용하여 []로 빈 범주를 채 웁니다. $filter은 megaArray에서 cats 배열을 쿼리하는 데 사용되었습니다.

나는 다음과 같은 오류가있어이를 실행하는 경우 :

Caused by: com.mongodb.MongoQueryException: Query failed with error code 2 and error message '>1 field in obj: { input: { $setUnion: [ { $ifNull: [ "$categories.category1", [] ] }, { $ifNull: [ "$categories.category2", [] ] }, { $ifNull: [ "$categories.category3", [] ] }, { $ifNull: [ "$categories.category4", [] ] }, { $ifNull: [ "$categories.category5", [] ] } ] }, as: "megaArray", cond: { $all: [ "$$megaArray", [ "factual" ] ] } }' 

나는 완전히 그 오른쪽에 보이는 무엇을 의미하는지 모르겠어요. 나는 또한 카테고리 객체가 항상 존재하는 것은 아니지만 이것이 중요한지 확실하지 않다는 것에 주목해야한다.

답변

1

당신은 당신이 먼저 'megaArray'을 만들기 위해 데이터를 투사하고 새로운 배열에 일치시킬 수 있습니다 이렇게하려면 집계 프레임 워크

를 사용하여 동일한 결과를 얻을 수 있습니다.

String [] cats = new String[] {"childrens", "signed"}; 

List<DBObject> theMegaArray = new ArrayList<>(); 

BasicDBObject theProjections = new BasicDBObject(); 

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 
    Object[] temp = new Object[] {cleanIdentifier, new Object[]{}}; 
    theMegaArray.add(new BasicDBObject("$ifNull", temp)); 
} 

theProjections.put("_id", 1); 
theProjections.put("pid", 1); 
theProjections.put("categories",1); 
theProjections.put("allCategories", new BasicDBObject("$setUnion", theMegaArray)); 

BasicDBObject theFilter = new BasicDBObject("allCategories", new BasicDBObject("$all", cats)); 

List<BasicDBObject> pipeline = new ArrayList<>(); 
pipeline.add(new BasicDBObject("$project", theProjections)); 
pipeline.add(new BasicDBObject("$match", theFilter)); 

AggregateIterable iterable = collection.aggregate(pipeline); 

위 코드 샘플은 프로젝트 단계에서 "allCategories"라는 새 배열을 추가 한 다음이 새 문서와 일치시킵니다.

또 다른 투사 단계

는 최종 출력

1

당신은 아래의 집계 파이프 라인을 사용할 수 있습니다에서 allCategories 배열을 제거하기 위해 추가 할 수 있습니다. 참조

쉘 검색어 :

db.collection.aggregate([{ 
    "$project": { 
     "pid": 1, 
     "categories": 1, 
     "filter": { 
      "$eq": [{ 
        "$setUnion": [{ 
         "$ifNull": ["$categories.category1", []] 
        }, { 
         "$ifNull": ["$categories.category2", []] 
        }, { 
         "$ifNull": ["$categories.category3", []] 
        }, { 
         "$ifNull": ["$categories.category4", []] 
        }, { 
         "$ifNull": ["$categories.category5", []] 
        }] 
       }, 
       ["childrens", "signed"] 
      ] 
     } 
    } 
}, { 
    "$match": { 
     "filter": true 
    } 
}]) 

자바 코드 :

String[] cats = {"childrens", "signed"}; 

// Combining the optional categories arrays 
BasicDBList theMegaArray = new BasicDBList(); 
for (int i = 1; i <= 5; i++) { 
     String identifier = "categories.category" + i; 
     String cleanIdentifier = "$" + identifier; 
     theMegaArray.add(new BasicDBObject("$ifNull", Arrays.asList(cleanIdentifier, Collections.EMPTY_LIST))); 
} 
BasicDBObject theData = new BasicDBObject("$setUnion", theMegaArray); 

// Add equals filter - Compare the arrays and output boolean filter field 
BasicDBObject theFilter = new BasicDBObject("$eq", Arrays.asList(theData, cats)); 

// Add projections to keep the output fields 
BasicDBObject theProjections = new BasicDBObject(); 
theProjections.put("filter", theFilter); 
theProjections.put("pid", 1); 
theProjections.put("categories", 1); 

// Add $project stage 
BasicDBObject theProject = new BasicDBObject("$project", theProjections); 

// Add $match stage to compare the boolean filter field to true to keep matching documents 
BasicDBObject theMatch = new BasicDBObject("$match", new BasicDBObject("filter", true)); 

// Add stages to piepline 
BasicDBList pipeline = new BasicDBList(); 
pipeline.add(theProject); 
pipeline.add(theMatch); 

// Run aggregation 
AggregateIterable iterable = collection.aggregate(pipeline);