[MONGODB] 여러 필드 MongoDB에 의해 기 값
MONGODB여러 필드 MongoDB에 의해 기 값
예를 들어, 나는이 문서가 :
{
"addr": "address1",
"book": "book1"
},
{
"addr": "address2",
"book": "book1"
},
{
"addr": "address1",
"book": "book5"
},
{
"addr": "address3",
"book": "book9"
},
{
"addr": "address2",
"book": "book5"
},
{
"addr": "address2",
"book": "book1"
},
{
"addr": "address1",
"book": "book1"
},
{
"addr": "address15",
"book": "book1"
},
{
"addr": "address9",
"book": "book99"
},
{
"addr": "address90",
"book": "book33"
},
{
"addr": "address4",
"book": "book3"
},
{
"addr": "address5",
"book": "book1"
},
{
"addr": "address77",
"book": "book11"
},
{
"addr": "address1",
"book": "book1"
}
그래서 내가 최고 N 주소와 주소 당 최고 M 책을 설명하는 요청을 할 수 on.How 예상 결과의 예 : 주소 1 | book_1 : 5 | book_2 : 10 | book_3 : 50 | 총 : 65 ______________________ 주소 2 | book_1 : 10 | book_2 : 10 | ... | book_M : 10 | 총 : M * 10 ... ______________________ addressN | book_1 : 20 | book_2 : 20 | ... | book_M : 20 | 총 : M * 20
해결법
-
==============================
1.현대 MongoDB를 릴리스에서는 그냥 기본 집계 결과 오프 $ 슬라이스이 무력 할 수 있습니다. "큰"결과를 각각 그룹화하는 대신 병렬 쿼리를 실행 (목록 데모는 대답의 끝에), 또는 서버 9377 해결하려면 $ 푸시에 항목의 수에 "한계"를 허용 할 기다립니다 배열.
현대 MongoDB를 릴리스에서는 그냥 기본 집계 결과 오프 $ 슬라이스이 무력 할 수 있습니다. "큰"결과를 각각 그룹화하는 대신 병렬 쿼리를 실행 (목록 데모는 대답의 끝에), 또는 서버 9377 해결하려면 $ 푸시에 항목의 수에 "한계"를 허용 할 기다립니다 배열.
db.books.aggregate([ { "$group": { "_id": { "addr": "$addr", "book": "$book" }, "bookCount": { "$sum": 1 } }}, { "$group": { "_id": "$_id.addr", "books": { "$push": { "book": "$_id.book", "count": "$bookCount" }, }, "count": { "$sum": "$bookCount" } }}, { "$sort": { "count": -1 } }, { "$limit": 2 }, { "$project": { "books": { "$slice": [ "$books", 2 ] }, "count": 1 }} ])
아직 SERVER-9377 해결하지만,이 릴리스 $ 조회에서 대신 "localFields"의 인수와 "foreignFields"옵션과 같은 '파이프 라인'표현 소요 새로운 "비 상관"옵션을 할 수 없습니다. 이 다음에 우리가 "상위 N"결과를 반환하기 위해 $ 제한을 적용 할 수있는 또 다른 파이프 라인 표현과 함께 "자체 조인"할 수 있습니다.
db.books.aggregate([ { "$group": { "_id": "$addr", "count": { "$sum": 1 } }}, { "$sort": { "count": -1 } }, { "$limit": 2 }, { "$lookup": { "from": "books", "let": { "addr": "$_id" }, "pipeline": [ { "$match": { "$expr": { "$eq": [ "$addr", "$$addr"] } }}, { "$group": { "_id": "$book", "count": { "$sum": 1 } }}, { "$sort": { "count": -1 } }, { "$limit": 2 } ], "as": "books" }} ])
다른 추가는 여기에 "참여"에 일치하는 항목을 선택하여 $ 일치를 사용하여 $ EXPR을 통해 변수를 보간 물론 능력이지만, 일반적인 전제는 내부 콘텐츠를 필터링 할 수있는 "파이프 라인 내에서 파이프 라인"입니다 부모에서 일치합니다. 그들은 모두 "파이프 라인"자신 때문에 우리는 개별적으로 각 결과를 제한 $ 할 수 있습니다.
이 병렬 쿼리를 실행하기 다음으로 좋은 옵션이 될 것입니다, 그리고 $ 일치 허용하고 "하위 파이프 라인"처리에 인덱스를 사용할 수 있다면 실제로 더 좋을 것이다. 이는 참조 문제가 묻습니다로 "$ 추진에 한계"를 사용하지 않습니다 그래서, 실제로 잘 작동해야 무언가를 제공합니다.
당신은 최고 "N"문제 우연히 발견 한 것 같다. 어떤면에서 문제가없는 정확한 당신이 물어 제한에 불구하고 해결하기 위해 매우 간단합니다 :
db.books.aggregate([ { "$group": { "_id": { "addr": "$addr", "book": "$book" }, "bookCount": { "$sum": 1 } }}, { "$group": { "_id": "$_id.addr", "books": { "$push": { "book": "$_id.book", "count": "$bookCount" }, }, "count": { "$sum": "$bookCount" } }}, { "$sort": { "count": -1 } }, { "$limit": 2 } ])
이제 당신이 같은 결과를 줄 것이다 :
{ "result" : [ { "_id" : "address1", "books" : [ { "book" : "book4", "count" : 1 }, { "book" : "book5", "count" : 1 }, { "book" : "book1", "count" : 3 } ], "count" : 5 }, { "_id" : "address2", "books" : [ { "book" : "book5", "count" : 1 }, { "book" : "book1", "count" : 2 } ], "count" : 3 } ], "ok" : 1 }
우리가 기본이 "책"선택 결과 만 필요한 양에 한정되지 않고 주소 값의 최고 결과를 얻을 할 동안, 그에서 요구하는 것과이 다릅니다 그래서.
아웃이 회전은 할 매우 어려운,하지만 복잡성이 당신이 일치해야하는 항목의 수에 따라 증가하지만이를 수행 할 수 있습니다. 그것을 간단하게 유지하기 위해 우리는이 경기에서 가장에서이 문제를 유지할 수 있습니다 :
db.books.aggregate([ { "$group": { "_id": { "addr": "$addr", "book": "$book" }, "bookCount": { "$sum": 1 } }}, { "$group": { "_id": "$_id.addr", "books": { "$push": { "book": "$_id.book", "count": "$bookCount" }, }, "count": { "$sum": "$bookCount" } }}, { "$sort": { "count": -1 } }, { "$limit": 2 }, { "$unwind": "$books" }, { "$sort": { "count": 1, "books.count": -1 } }, { "$group": { "_id": "$_id", "books": { "$push": "$books" }, "count": { "$first": "$count" } }}, { "$project": { "_id": { "_id": "$_id", "books": "$books", "count": "$count" }, "newBooks": "$books" }}, { "$unwind": "$newBooks" }, { "$group": { "_id": "$_id", "num1": { "$first": "$newBooks" } }}, { "$project": { "_id": "$_id", "newBooks": "$_id.books", "num1": 1 }}, { "$unwind": "$newBooks" }, { "$project": { "_id": "$_id", "num1": 1, "newBooks": 1, "seen": { "$eq": [ "$num1", "$newBooks" ]} }}, { "$match": { "seen": false } }, { "$group":{ "_id": "$_id._id", "num1": { "$first": "$num1" }, "num2": { "$first": "$newBooks" }, "count": { "$first": "$_id.count" } }}, { "$project": { "num1": 1, "num2": 1, "count": 1, "type": { "$cond": [ 1, [true,false],0 ] } }}, { "$unwind": "$type" }, { "$project": { "books": { "$cond": [ "$type", "$num1", "$num2" ]}, "count": 1 }}, { "$group": { "_id": "$_id", "count": { "$first": "$count" }, "books": { "$push": "$books" } }}, { "$sort": { "count": -1 } } ])
그 사실은 당신에게 정상이 "주소"항목에서 상위 2 "책을"줄 것이다 그래서.
하지만 내 돈을 위해, 다음 첫 번째 양식 단순히 "조각"최초의 "N"요소를 취할 반환되는 배열의 요소와 숙박.
데모 코드는 v8.x 및 v10.x 릴리스 NodeJS의 현재 LTS 버전과 사용에 적합하다. 즉 대부분 비동기 / await를 구문이지만, 심지어 다시 일반 콜백 구현에 작은 일반 약속을 변경 또는과 그러한 제한이 일반적인 흐름 내에서 정말 아무것도, 그리고 적응이 없습니다.
하는 index.js
const { MongoClient } = require('mongodb'); const fs = require('mz/fs'); const uri = 'mongodb://localhost:27017'; const log = data => console.log(JSON.stringify(data, undefined, 2)); (async function() { try { const client = await MongoClient.connect(uri); const db = client.db('bookDemo'); const books = db.collection('books'); let { version } = await db.command({ buildInfo: 1 }); version = parseFloat(version.match(new RegExp(/(?:(?!-).)*/))[0]); // Clear and load books await books.deleteMany({}); await books.insertMany( (await fs.readFile('books.json')) .toString() .replace(/\n$/,"") .split("\n") .map(JSON.parse) ); if ( version >= 3.6 ) { // Non-correlated pipeline with limits let result = await books.aggregate([ { "$group": { "_id": "$addr", "count": { "$sum": 1 } }}, { "$sort": { "count": -1 } }, { "$limit": 2 }, { "$lookup": { "from": "books", "as": "books", "let": { "addr": "$_id" }, "pipeline": [ { "$match": { "$expr": { "$eq": [ "$addr", "$$addr" ] } }}, { "$group": { "_id": "$book", "count": { "$sum": 1 }, }}, { "$sort": { "count": -1 } }, { "$limit": 2 } ] }} ]).toArray(); log({ result }); } // Serial result procesing with parallel fetch // First get top addr items let topaddr = await books.aggregate([ { "$group": { "_id": "$addr", "count": { "$sum": 1 } }}, { "$sort": { "count": -1 } }, { "$limit": 2 } ]).toArray(); // Run parallel top books for each addr let topbooks = await Promise.all( topaddr.map(({ _id: addr }) => books.aggregate([ { "$match": { addr } }, { "$group": { "_id": "$book", "count": { "$sum": 1 } }}, { "$sort": { "count": -1 } }, { "$limit": 2 } ]).toArray() ) ); // Merge output topaddr = topaddr.map((d,i) => ({ ...d, books: topbooks[i] })); log({ topaddr }); client.close(); } catch(e) { console.error(e) } finally { process.exit() } })()
books.json
{ "addr": "address1", "book": "book1" } { "addr": "address2", "book": "book1" } { "addr": "address1", "book": "book5" } { "addr": "address3", "book": "book9" } { "addr": "address2", "book": "book5" } { "addr": "address2", "book": "book1" } { "addr": "address1", "book": "book1" } { "addr": "address15", "book": "book1" } { "addr": "address9", "book": "book99" } { "addr": "address90", "book": "book33" } { "addr": "address4", "book": "book3" } { "addr": "address5", "book": "book1" } { "addr": "address77", "book": "book11" } { "addr": "address1", "book": "book1" }
-
==============================
2.아래와 같은 집계 함수를 사용하여 :
아래와 같은 집계 함수를 사용하여 :
[ {$group: {_id : {book : '$book',address:'$addr'}, total:{$sum :1}}}, {$project : {book : '$_id.book', address : '$_id.address', total : '$total', _id : 0}} ]
당신이 다음과 같은 결과를 줄 것이다 :
{ "total" : 1, "book" : "book33", "address" : "address90" }, { "total" : 1, "book" : "book5", "address" : "address1" }, { "total" : 1, "book" : "book99", "address" : "address9" }, { "total" : 1, "book" : "book1", "address" : "address5" }, { "total" : 1, "book" : "book5", "address" : "address2" }, { "total" : 1, "book" : "book3", "address" : "address4" }, { "total" : 1, "book" : "book11", "address" : "address77" }, { "total" : 1, "book" : "book9", "address" : "address3" }, { "total" : 1, "book" : "book1", "address" : "address15" }, { "total" : 2, "book" : "book1", "address" : "address2" }, { "total" : 3, "book" : "book1", "address" : "address1" }
나는 꽤 당신의 예상 된 결과 형식을 얻을 당신이 필요로하는 일이 자유롭게 수정할하지 않았다.
-
==============================
3.쿼리 아래의 원하는 응답에 주어진 정확히 같은 결과를 제공 할 것입니다 :
쿼리 아래의 원하는 응답에 주어진 정확히 같은 결과를 제공 할 것입니다 :
db.books.aggregate([ { $group: { _id: { addresses: "$addr", books: "$book" }, num: { $sum :1 } } }, { $group: { _id: "$_id.addresses", bookCounts: { $push: { bookName: "$_id.books",count: "$num" } } } }, { $project: { _id: 1, bookCounts:1, "totalBookAtAddress": { "$sum": "$bookCounts.count" } } } ])
응답은 아래와 같이보고합니다 :
/* 1 */ { "_id" : "address4", "bookCounts" : [ { "bookName" : "book3", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 2 */ { "_id" : "address90", "bookCounts" : [ { "bookName" : "book33", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 3 */ { "_id" : "address15", "bookCounts" : [ { "bookName" : "book1", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 4 */ { "_id" : "address3", "bookCounts" : [ { "bookName" : "book9", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 5 */ { "_id" : "address5", "bookCounts" : [ { "bookName" : "book1", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 6 */ { "_id" : "address1", "bookCounts" : [ { "bookName" : "book1", "count" : 3 }, { "bookName" : "book5", "count" : 1 } ], "totalBookAtAddress" : 4 }, /* 7 */ { "_id" : "address2", "bookCounts" : [ { "bookName" : "book1", "count" : 2 }, { "bookName" : "book5", "count" : 1 } ], "totalBookAtAddress" : 3 }, /* 8 */ { "_id" : "address77", "bookCounts" : [ { "bookName" : "book11", "count" : 1 } ], "totalBookAtAddress" : 1 }, /* 9 */ { "_id" : "address9", "bookCounts" : [ { "bookName" : "book99", "count" : 1 } ], "totalBookAtAddress" : 1 }
from https://stackoverflow.com/questions/22932364/mongodb-group-values-by-multiple-fields by cc-by-sa and MIT license
'MONGODB' 카테고리의 다른 글
[MONGODB] 어떻게 NodeJs 응용 프로그램 및 모듈에서 MongoDB를 적절히 재사용 연결에 (0) | 2019.11.29 |
---|---|
[MONGODB] 몽구스 통해 몽고 배열 푸시 상품 (0) | 2019.11.29 |
[MONGODB] 어떻게 Node.js를 웹 응용 프로그램에서 MongoDB의 연결을 관리합니까? (0) | 2019.11.29 |
[MONGODB] 더 정렬 순서가 지정되지 않은 경우 어떻게 MongoDB를 정렬 기록을합니까? (0) | 2019.11.29 |
[MONGODB] 방법 MongoDB를 가진 하위 필터링 배열 [중복] (0) | 2019.11.29 |