2013-07-01 2 views
2

MongoDB를 사용하고 있으며 그룹 내의 레코드를 정렬 및 건너 뛰기를 원합니다.Mongo DB - 그룹 내 정렬 및 생략

{ 
    "_id" : ObjectId("51cd7274267d959cb9f95cea"), 
    "creation_time" : 100, 
    "delivered" : true, 
    "id" : 1, 
    "user_id" : 10 
} 

지금 내가 원하는 사용자 당 모든 문서의 _id (user_id) 아니 : 아래

는 샘플 데이터입니다. 사용자를위한 문서의 수는 4 개 이상입니다. 또한이 4 개의 문서를 건너 뛰고 난 후에 _id 개의 문서를 원합니다. 따라서 사용자가 6 개의 문서를 가지고있는 경우 마지막 두 개의 문서를 _id (creation_time으로 정렬)하여 두 개의 이전 문서를 다른 db에 보관할 수 있습니다.

나는 다음과 같은 쿼리를 사용하고 있습니다 :

db.newsdb.aggregate([ 
{ 
    $match: { 
     delivered: true 
    } 
}, 
{ 
    $group: { 
     _id: { 
      user_id: "$user_id", 
      creation_time: "$creation_time" 
     } 
    } 
} 
]) 

하는 것은 이제 문제는 각 사용자와 모든 사용자의 문서에 문서에 $sort$skip 작업을 수행 할 것입니다. 그래서 저는 다음과 같은 것을 원합니다 :

{ 
    $group: { 
     _id: { 
      user_id: "$user_id", 
      creation_time: "$creation_time" 
     } 
    }, 
    $sort: { 
     user_id:1, 
     creation_time:1 
    }, 
    $skip: 4 
} 

그러나 mongo db는 지원하지 않습니다. 다음 오류가 발생합니다 :

Error: Printing Stack Trace 
    at printStackTrace (src/mongo/shell/utils.js:37:7) 
    at DBCollection.aggregate (src/mongo/shell/collection.js:897:1) 
    at (shell):1:11 
Mon Jul 1 14:47:55.762 JavaScript execution failed: aggregate failed: { 
    "errmsg" : "exception: A pipeline stage specification object must contain exactly one field.", 
    "code" : 16435, 
    "ok" : 0 
} at src/mongo/shell/collection.js:L898 
+0

왜'$ ceation_time'을'group'에서 사용합니까? 많은 문서가 동일한 user_id를 갖지만 생성 시간이 다를 수 있습니까? – Schaliasos

+0

@Schaliasos'$ creation_time'을 사용하지 않으면 사용자의 모든 문서를 한 행에 그룹화합니다. 그러나 나는 사용자를 위해 모든 문서를 원하고 그 문서에서 작업 (정렬 및 건너 뛰기)을 더 할 수 있습니다. 이제 문제는 최종 결과가 동일 할 때이 그룹의 중요성이 무엇인가하는 것입니다. 그래서 그 질문에 대한 답은 모든 사용자의 모든 문서가 아닌 모든 문서에 대해'sort'와'skip'을 수행하기를 원합니다.나는 그것들을 먼저'user_id'에 의해 그룹화하여 더 많은 작업을 할 수 있다고 생각했습니다. 그보다 더 좋은 아이디어가 있다면 제안 할 수 있습니다. –

+0

그러면 아마도'group' 문이 필요 없을 것입니다. – Schaliasos

답변

0

현재 집계 프레임 워크에서이 작업을 수행 할 방법이 없습니다.

각 사용자에 대해 별도의 쿼리를 만들어야합니다. 당신이 할 수있는 최선의 각 당신에게 4 위로되지 않은 문서를 제공하기 위해 쿼리를 실행하는 모든 사용자에 대해 반복 뭔가 :

[user list].forEach(function(u) { 
var listToArchive = db.newsdb.find({user_id: u},{_id:1}).sort({creation_time:-1}).skip(4); 
/* do what you need to with listToArchive _id's */ 
}) 
+0

mapreduce로도 처리 할 수 ​​있지만 여러 개의 쿼리 (인덱스가있는 경우)가 크게 발생합니다 전체 컬렉션에서 mapreduce보다 빠릅니다. –

+0

4 개의 문서를 user_id 객체에 포함시키려는 경우 캡슐화 된 배열을 유지 관리 할 수있는 2.4 기능을 사용할 수 있습니다. 각 사용자는 4 개의 최신 문서 배열을 가질 수 있습니다. 이렇게하면 정리가 간단 해집니다. 새 문서를 배열에 삽입하면 자동으로 수행됩니다. –

0

을 너무 생각 후를, 나는 이후지도-감소하여 해결책을 알아 냈어 집계 프레임 워크를 사용할 수없는 것 같습니다.

다음은 단순 그룹 문서 user_id에 의한 축소 기능입니다.

var mapf = function() { 
    emit(this.user_id, { 
     _id: this._id, 
     creation_time: this.creation_time 
    }) 
} 

감소 기능을 사용할 때 최소한 4 개의 항목이 있는지 확인합니다. 참이면 values 배열이 creation_time 순으로 정렬되고 처음 네 개의 문서는 건너 뜁니다.

var redf = function (key, values) { 
    var result = {}; 
    if (values.length > 4) { 
     values.sort(function (a, b) { 
      return a.creation_time > b.creation_time; 
     }); 

     // unfortunately, mongodb doesn't support array as result of reduce function 
     result['oids'] = values.slice(3); 
    } 

    return result; 
} 

이제 map-reduce 명령을 실행하십시오. 결과는 plus_four_users 컬렉션에 삽입됩니다.

db.newsdb.mapReduce(mapf, redf, { out : "plus_four_users" }) 

이 그런 일이 발생할 것입니다 : 당신을 도울 수

> db.newsdb.find({}, { user_id : 1, creation_time : 1 }) 
{ "_id" : ObjectId("51d612423dab6225ca6e6d36"), "creation_time" : 100, "user_id" : 10 } 
{ "_id" : ObjectId("51d612503dab6225ca6e6d37"), "creation_time" : 200, "user_id" : 10 } 
{ "_id" : ObjectId("51d612553dab6225ca6e6d38"), "creation_time" : 300, "user_id" : 10 } 
{ "_id" : ObjectId("51d612593dab6225ca6e6d39"), "creation_time" : 400, "user_id" : 10 } 
{ "_id" : ObjectId("51d6125d3dab6225ca6e6d3a"), "creation_time" : 500, "user_id" : 10 } 
{ "_id" : ObjectId("51d6126f55ebf2ff5a13d1c9"), "creation_time" : 600, "user_id" : 10 } 
{ "_id" : ObjectId("51d6127455ebf2ff5a13d1ca"), "creation_time" : 300, "user_id" : 11 } 
{ "_id" : ObjectId("51d6127955ebf2ff5a13d1cb"), "creation_time" : 400, "user_id" : 11 } 
{ "_id" : ObjectId("51d6127c55ebf2ff5a13d1cc"), "creation_time" : 500, "user_id" : 11 } 
{ "_id" : ObjectId("51d6127f55ebf2ff5a13d1cd"), "creation_time" : 600, "user_id" : 11 } 
{ "_id" : ObjectId("51d6128555ebf2ff5a13d1ce"), "creation_time" : 700, "user_id" : 11 } 



> db.plus_four_users.find().pretty() 
{ 
    "_id": 10, 
    "value": { 
     "oids": [ 
      { 
       "_id": ObjectId("51d6125d3dab6225ca6e6d3a"), 
       "creation_time": 500 
      }, 
      { 
       "_id": ObjectId("51d6126f55ebf2ff5a13d1c9"), 
       "creation_time": 600 
      } 
     ] 
    } 
} 
{ 
    "_id": 11, 
    "value": { 
     "oids": [ 
      { 
       "_id": ObjectId("51d6128555ebf2ff5a13d1ce"), 
       "creation_time": 700 
      } 
     ] 
    } 
} 

희망!

+0

map-reduce로 수행 할 수 있지만 구현이 올바르지 않습니다. 간단한 테스트로서 하나의 user_id가 하나의 문서 만 가지고있는 샘플 데이터 세트로 실행 해보십시오. 또한 대용량 데이터 세트에서 올바르게 작동하지 않을 것이고, 샤드 컬렉션에서 확실히 깨질 것입니다. –

+0

당신은 바로 @AsyaKamsky입니다. 이 MR 기능의 문제점은 감소 기능에 대한 멱등 원 (Imempotence)의 부족입니다. 사실, Yatendra Goel은 몇 가지 기분 전환을 만들었고 그 해결책을 찾았습니다. http://stackoverflow.com/questions/17485957/mongodb-map-reduce-complete-data-is-not-returned –

+1

실제로 나는 그에게 해결책을주었습니다. : https://groups.google.com/d/msg/mongodb-user/EhNEbyB9UBA/YgwELC3e91sJ –