mongodb นับจำนวนของค่าที่แตกต่างกันต่อฟิลด์ / คีย์


110

มีแบบสอบถามสำหรับการคำนวณจำนวนค่าที่แตกต่างกันในเขตข้อมูลใน DB

ฉันมีเขตข้อมูลสำหรับประเทศและมีค่าประเทศ 8 ประเภท (สเปนอังกฤษฝรั่งเศส ฯลฯ ... )

หากมีคนเพิ่มเอกสารในประเทศใหม่ฉันต้องการให้แบบสอบถามส่งคืน 9

มีวิธีที่ง่ายกว่าแล้วจัดกลุ่มและนับหรือไม่?


2
คุณได้ดูที่กรอบการรวมหรือไม่?
WiredPrairie


ซ้ำเป็นไปได้ของMongoDB นับเลือก (ที่แตกต่างกัน x) ในการจัดทำดัชนีคอลัมน์ - นับผลที่ไม่ซ้ำกันสำหรับชุดข้อมูลขนาดใหญ่ ฉันโพสต์คำตอบของฉันที่นั่น
ผู้เชี่ยวชาญ

คำตอบ:


203

MongoDB มีdistinctคำสั่งที่ส่งคืนอาร์เรย์ของค่าที่แตกต่างกันสำหรับฟิลด์ คุณสามารถตรวจสอบความยาวของอาร์เรย์เพื่อนับจำนวน

มีตัวdb.collection.distinct()ช่วยเชลล์เช่นกัน:

> db.countries.distinct('country');
[ "Spain", "England", "France", "Australia" ]

> db.countries.distinct('country').length
4

50
สิ่งนี้จะใช้ไม่ได้จริงๆหากจำนวนค่าที่แตกต่างกันของคุณสูงเกินไป ... หากคุณกำลังดูชื่อที่แตกต่างกันของผู้คนในโลกหรือบางสิ่งบางอย่าง คุณมีคำตอบที่ชั่ง?
การใน

3
1+ สำหรับความยาว ฉันกำลังดิ้นรนเพื่อหาอะไรแบบนั้น ขอบคุณ.
Adeel Ahmad

ฉันไม่รู้ว่าทำไมพวกเขาถึงไม่ใช้ count () ที่นั่นด้วย
Marian Klühspies

1
@ MarianKlühspies - เนื่องจากเป็นเพียงอาร์เรย์จาวาสคริปต์ซึ่งใช้คุณสมบัติความยาวเพื่อนับจำนวนองค์ประกอบ
UpTheCreek

สิ่งที่ฉันกำลังมองหา ... TY
Maulzey

117

นี่คือตัวอย่างของการใช้ aggregation API เพื่อทำให้กรณีซับซ้อนขึ้นเรากำลังจัดกลุ่มตามคำที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่จากคุณสมบัติอาร์เรย์ของเอกสาร

db.articles.aggregate([
    {
        $match: {
            keywords: { $not: {$size: 0} }
        }
    },
    { $unwind: "$keywords" },
    {
        $group: {
            _id: {$toLower: '$keywords'},
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: { $gte: 2 }
        }
    },
    { $sort : { count : -1} },
    { $limit : 100 }
]);

ที่ให้ผลลัพธ์เช่น

{ "_id" : "inflammation", "count" : 765 }
{ "_id" : "obesity", "count" : 641 }
{ "_id" : "epidemiology", "count" : 617 }
{ "_id" : "cancer", "count" : 604 }
{ "_id" : "breast cancer", "count" : 596 }
{ "_id" : "apoptosis", "count" : 570 }
{ "_id" : "children", "count" : 487 }
{ "_id" : "depression", "count" : 474 }
{ "_id" : "hiv", "count" : 468 }
{ "_id" : "prognosis", "count" : 428 }

2
ลงชื่อเข้าใช้เพื่อ + คำตอบนี้ ขอบคุณ! btw ถ้าคุณกำลังทำมันในสนามที่ไม่ซ้ำกันให้ลบเส้นคลายออก
Richie Rich

@RichieRich unwindเป็นสิ่งที่จำเป็นเนื่องจากรหัสกำลังจัดกลุ่มค่าแต่ละค่าของฟิลด์อาร์เรย์ซึ่งตรงกับวิธีการdistinctทำงาน
Paul

@ พอลสิ่งที่ริชชี่พูดก็คือถ้าการจัดกลุ่มเสร็จสิ้นเพียงแค่ฟิลด์ "ปกติ" (สตริง, int ฯลฯ ) คุณก็ไม่จำเป็นต้องมีขั้นตอนคลายเครียด ไม่ถูกต้องหรือ
Guyarad

@guyarad unwindเป็นสิ่งที่จำเป็นเมื่อทำงานกับอาร์เรย์
พอล

+1 สำหรับคำตอบคือสิ่งที่ฉันกำลังทำอยู่ แต่มีเสน่ห์ที่แตกต่างกันออกไป แต่นี่เป็นเพียงทองคำ :) - อย่างไรก็ตามฉันต้องอ่านเพิ่มเติมเกี่ยวกับการรวมเพื่อให้ได้ชุดผลลัพธ์ที่ต้องการเพื่อกรองข้อมูล
Talha

21

ด้วย MongoDb 3.4.4 และใหม่กว่าคุณสามารถใช้ประโยชน์จากการใช้$arrayToObjectตัวดำเนินการและ$replaceRootไปป์ไลน์เพื่อรับจำนวน

ตัวอย่างเช่นสมมติว่าคุณมีกลุ่มผู้ใช้ที่มีบทบาทที่แตกต่างกันและคุณต้องการคำนวณจำนวนบทบาทที่แตกต่างกัน คุณจะต้องเรียกใช้ไปป์ไลน์รวมต่อไปนี้:

db.users.aggregate([
    { "$group": {
        "_id": { "$toLower": "$role" },
        "count": { "$sum": 1 }
    } },
    { "$group": {
        "_id": null,
        "counts": {
            "$push": { "k": "$_id", "v": "$count" }
        }
    } },
    { "$replaceRoot": {
        "newRoot": { "$arrayToObject": "$counts" }
    } }    
])

ตัวอย่างผลลัพธ์

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}

นี่ไม่ใช่คำตอบสำหรับคำถาม แต่ก็มีประโยชน์ .distinct()ฉันสงสัยว่าการดำเนินการนี้เมื่อเทียบกับ
Redsandro

9

คุณสามารถใช้ประโยชน์จากMongo เชลล์ส่วนขยาย มันเป็นการนำเข้า. js เดียวที่คุณสามารถต่อท้ายของคุณ$HOME/.mongorc.jsหรือทางโปรแกรมได้หากคุณกำลังเข้ารหัสใน Node.js / io.js ด้วย

ตัวอย่าง

สำหรับแต่ละค่าที่แตกต่างกันของเขตข้อมูลจะนับจำนวนที่เกิดขึ้นในเอกสารที่เลือกกรองตามแบบสอบถาม

> db.users.distinctAndCount('name', {name: /^a/i})

{
  "Abagail": 1,
  "Abbey": 3,
  "Abbie": 1,
  ...
}

พารามิเตอร์ฟิลด์อาจเป็นอาร์เรย์ของฟิลด์

> db.users.distinctAndCount(['name','job'], {name: /^a/i})

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}

ฉันจะนำเข้าสิ่งนี้ในโหนดได้อย่างไร
Salmaan P

require("./script.js")ฉันคิดว่า
evandrix

ถูกต้อง แต่ฉันไม่สามารถรับฟังก์ชั่นภายในได้ ฉันจะใช้มันได้อย่างไร พวกมันถูกกำหนดให้เป็น db.protoptype.distinctAndCount
Salmaan P

มีส่วนวิธีการใน readme ของ repo (RTFM! 1 !! 1!) โดยทั่วไปให้ใส่.mongorc.jsไฟล์ลงใน dir ที่บ้านของคุณ เสร็จแล้ว
Janis F

7

หากต้องการค้นหาความแตกต่างในfield_1คอลเลกชัน แต่เราต้องการWHEREเงื่อนไขบางอย่างเกินกว่าที่เราจะทำได้ดังต่อไปนี้:

db.your_collection_name.distinct('field_1', {WHERE condition here and it should return a document})

ดังนั้นค้นหาหมายเลขที่แตกต่างnamesจากคอลเล็กชันที่อายุ> 25 จะเป็นดังนี้:

db.your_collection_name.distinct('names', {'age': {"$gt": 25}})

หวังว่าจะช่วยได้!


0

ฉันใช้แบบสอบถามนี้:

var collection = "countries"; var field = "country"; 
db[collection].distinct(field).forEach(function(value){print(field + ", " + value + ": " + db.hosts.count({[field]: value}))})

เอาท์พุต:

countries, England: 3536
countries, France: 238
countries, Australia: 1044
countries, Spain: 16

การค้นหานี้จะทำให้ค่าทั้งหมดแตกต่างกันก่อนจากนั้นจึงนับจำนวนครั้งที่เกิดขึ้นสำหรับแต่ละค่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.