pertanyaan kelompok mongo bagaimana menjaga bidang


97

Semua orang. Dalam kueri grup mongo, hasilnya hanya menampilkan kunci dalam argumen. Bagaimana cara menyimpan dokumen pertama di setiap grup seperti grup kueri mysql. sebagai contoh:

-------------------------------------------------------------------------
|  name  | age  |  sex  | province |   city   |   area   |   address     |
-------------------------------------------------------------------------
| ddl1st | 22   | 纯爷们 |  BeiJing |  BeiJing | ChaoYang | QingNianLu    |
| ddl1st | 24   | 纯爷们 |  BeiJing |  BeiJing | XuHui    | ZhaoJiaBangLu |
|  24k   | 220  | ...   |  ....    |  ...     | ...      | ...           |
-------------------------------------------------------------------------



db.users.group({key: { name: 1},reduce: function ( curr, result ) { result.count ++ },initial: {count : 0 } })

hasil:

[
{
    "name" : "ddl1st",
    "count" : 1
},
{
    "name" : "24k",
    "count" : 1
}
]

Cara mendapatkan yang berikut ini:

[
   {
   "name" : "ddl1st",
   "age" : 22,
   "sex" : "纯爷们",
   "province" : "BeiJing",
   "city" : "BeiJing",
   "area" : "ChaoYang",
   "address" : "QingNianLu",
   "count" : 1
   },
   {
   "name" : "24k",
   "age" : 220,
   "sex" : "...",
   "province" : "...",
   "city" : "...",
   "area" : "...",
   "address" : "...",
   "count" : 1
}
]

Jawaban:


216

Jika Anda ingin menyimpan informasi tentang entri pertama yang cocok untuk setiap grup, Anda dapat mencoba menggabungkan seperti:

db.test.aggregate({
  $group: {
   _id : '$name',
   name : { $first: '$name' },
   age : { $first: '$age' },
   sex : { $first: '$sex' },
   province : { $first: '$province' },
   city : { $first: '$city' },
   area : { $first: '$area' },
   address : { $first: '$address' },
   count : { $sum: 1 }
  }
}

4
Mengapa Anda membutuhkan {$first: '$age'}dll? Apakah mungkin untuk memilikinya age: $age?
Lightalchemist

7
@lightalchemist Itu tidak mungkin. Ini semacam tipuan untuk memberi tahu 'kelompok' apa yang harus dipilih.
TechWisdom

4
Bagaimana jika alih-alih menghitung agregasi ini melakukan $ max atau $ min untuk usia? $ First belum tentu cocok dengan usia minimal atau maksimal yang ditemukan untuk bidang lain. Bagaimana cara mengatasinya?
Juliomac

2
Ini tidak bekerja, itu dikelompokkan berdasarkan bidang lain yang tidak diinginkan.
Jack Cole

1
@Juliomac, saya percaya jika output yang Anda inginkan adalah $ max / $ min dan menjaga bidang yang tidak ada di $group_id, Anda dapat $sortsebelumnya dengan bidang yang diinginkan kemudian mengelompokkan dan menggunakan $firstatau $lastoperator di bidang apa pun. Saat terakumulasi, gagasan untuk memasukkan bidang lain (yang diakumulasikan / disalurkan / dikurangi) tidak masuk akal bahkan secara teoritis. Namun, pengurutan sebelumnya sebenarnya tidak efisien dibandingkan dengan pengurutan setiap grup di dalam dirinya sendiri karena algoritme pengurutan lebih kompleks daripada O (n). Saya berharap akan ada cara yang lebih baik di MongoDB.
Vemulo

16

Ngomong-ngomong, jika Anda ingin menyimpan tidak hanya dokumen pertama, Anda dapat menggunakan $ addToSet Misalnya:

db.test.aggregate({
  $group: {
    _id: '$name',
    name : { $addToSet: '$name' }
    age : { $addToSet: '$age' },
    count: { $sum: 1 }
  }
}

1
Terima kasih! Lebih baik (hindari mengacaukan pesanan dengan Set): data: {$ addToSet: {name: '$ name', _id: '$ _id', age: '$ age'}}
Benoit

14

[diedit untuk menyertakan saran komentar]

Saya datang ke sini mencari jawaban tetapi tidak senang dengan jawaban yang dipilih (terutama mengingat usianya). Saya menemukan jawaban ini yang merupakan solusi yang lebih baik (diadaptasi):

db.test.aggregate({
  $group: {
    _id: '$name',
   person: { "$first": "$$ROOT" },
   count: { $sum: 1 }
  },
  {
    "$replaceRoot": { "newRoot": { "$mergeObjects": ["$person", { count: "$count" }]} }
  }
}

3
TAPI, Anda kehilangan countlapangan. Anda perlu menggunakan $mergeObjectsuntuk menyimpannya.
0zkr PM

1
Untuk menguraikan komentar 0zkr tentang menggunakan $ mergeObjects dan membantu orang lain dengan sintaks, sintaks pipeline terakhir adalah{"$replaceRoot": {"newRoot": {"$mergeObjects": ["$person", {count: "$count"}]}}}
Jerren Saunders

7

Anda bisa mencobanya

db.test.aggregate({
      { $group: 
            { _id: '$name',count: { $sum: 1 }, data: { $push: '$$ROOT' } } },
      {
        $project: {
          _id:0,
          data:1,
          count :1
        }
      }

}

4

Ini yang saya lakukan, itu berfungsi dengan baik.

db.person.aggregate([
{
  $group: { _id: '$name'}, // pass the set of field to be grouped
   age : { $first: '$age' }, // retain remaining field
   count: { $sum: 1 } // count based on your group
},
{
  $project:{
       name:"$_id.name",
       age: "$age",
       count: "$count",
       _id:0 
  }
}])

4

Hanya pembaruan cepat jika seseorang menghadapi masalah yang sama dengan dokumen dengan berbagai bidang. Seseorang dapat menggunakan kekuatan menggabungkan $replaceRoottahap pipa dan $mergeObjectsoperator pipa.

db.users.aggregate([
  {
    $group: {
      _id: '$name',
      user: { $first: '$$ROOT' },
      count: { $sum: 1 }
    },
  },
  {
    $replaceRoot: {
      newRoot: { $mergeObjects: [{ count: '$count' }, '$user'] }
    }
  }
])

4

Gunakan $firstdengan $$ROOTdokumen dan kemudian gunakan $replaceRootdengan bidang pertama.

db.test.aggregate([
  { "$group": {
    "_id": "$name",
    "doc": { "$first": "$$ROOT" }
  }},
  { "$replaceRoot": { "newRoot": "$doc" }}
])

Ini sangat membantu! Terima kasih!! Saya telah mencari beberapa lama, tetapi tidak dapat menemukan apa yang saya butuhkan. Ini sempurna!
The Student Soul

Jawaban ini 'to the point' dan sempurna. Terima kasih!
M. Nunisa

1

Saya tidak tahu tentang .grouphelper, tetapi jika Anda lebih suka menggunakan Aggregation Framework , Anda harus menentukan bidang mana yang akan dikembalikan. Koreksi saya jika saya salah, tetapi dalam SQL Anda harus tetap melakukannya.

Nah, inilah cara Anda melakukannya dengan Kerangka Agregasi yang disebutkan sebelumnya:

db.test.aggregate({
  $group: {
    _id: { name: "$name", city: "$city", fieldName: "$fieldName" },
    count: { $sum: 1 }
  }
})

10
terima kasih atas bantuannya. dalam kueri ini adalah kelompok bidang tertentu, saya hanya ingin kelompok dengan satu bidang, dan kemudian hasil yang lain menentukan bidang. ada ide bagus?
plus atau

1

Saya membuat fungsi ini untuk menggeneralisasi membalikkan tahap bersantai ... beri tahu saya jika kalian menemukan bug dengannya, tetapi berfungsi dengan baik untuk saya!

const createReverseUnwindStages = unwoundField => {
  const stages = [
    //
    // Group by the unwound field, pushing each unwound value into an array,
    //
    // Store the data from the first unwound document
    // (which should all be the same apart from the unwound field)
    // on a field called data.
    // This is important, since otherwise we have to specify every field we want to keep individually.
    //
    {
      $group: {
        _id: '$_id',
        data: {$first: '$$ROOT'},
        [unwoundField]: {$push: `$${unwoundField}`},
      },
    },

    //
    // Copy the array of unwound fields resulting from the group into the data object,
    // overwriting the singular unwound value
    //
    {
      $addFields: {[`data.${unwoundField}`]: `$${unwoundField}`},
    },

    //
    // Replace the root with our data object
    //
    {
      $replaceRoot: {
        newRoot: '$data',
      },
    },
  ]

  return stages
}

Paling baik jika dokumen ke dalam koleksi yang sama memiliki nama bidang yang berbeda.
pengguna7364588

0

Jika Anda ingin memproyeksikan semua bidang dokumen, gunakan kueri di bawah ini.

db.persons.aggregate({
      { $group: { _id: '$name', data: { $push: '$$ROOT' }, total: { $sum: 1 }} },
      {
        $project: {
          _id:0,
          data:1,
          total :1
        }
      }
}

-1

Inilah jawabannya >>>>

    $m = new \MongoDB\Driver\Manager();

    $command = new \MongoDB\Driver\Command([
        'aggregate' => 'mytestusers',
        'pipeline' => [
            ['$match' => ['name' => 'Pankaj Choudhary']],

            ['$unwind'=>'$skills'],
            ['$lookup' => array('from'=>'mytestskills','localField'=>'skills','foreignField'=>'_id','as'=>'sdfg')],
            ['$unwind'=>'$sdfg'],

            ['$group'=>array('_id'=>array('_id'=>'$_id','name'=>'$name','email'=>'$email'),'skills'=>array('$push'=>'$skills'),'sdfg'=>array('$push'=>'$sdfg'))],


        ],
        'cursor' => new \stdClass,
    ]);
    $cursor = $m->executeCommand('targetjob-plus', $command);
    $result = $cursor->toArray();

atur tabel input Anda terlebih dahulu
Pankaj Cheema
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.