mongodb React性mongo族元素并计数

c0vxltue  于 2023-11-17  发布在  Go
关注(0)|答案(1)|浏览(142)

我有一个MongoDB数据库,其中存储不同的文件,这些文件可以是pngjpgpdf,这里有一个例子:

{
    "_id" : "id of the document",
    "metadata" : {
        "s" : "documents",
        "u" : "id of the owner",
        "d" : ""
    },
    "filename" : "El-jugador-Fedor-Dostoyevski.pdf",
    "contentType" : "application/pdf",
}

字符串
我删除了一些不相关的字段,文档的类型由contentType字段给出,我想要的是使用Scala和ReactiveMongo获得每种类型文件的计数
我已经这样做了,但是做了三次咨询,这样:

def contentTypeStats(implicit ec: ExecutionContext): Future[ContentTypesDTO] = {
    collectionFactory.collection().flatMap(collection => {

      val filterDocuments = BSONDocument("metadata.s" -> BSONDocument("$ne" -> "thumbnail"))//don't want count thumbnails, only documents
      
      val filterPNG = BSONDocument(filterDocuments, "contentType" -> "image/png")
      val filterJPG = BSONDocument(filterDocuments, "contentType" -> "image/jpeg")
      val filterPDF = BSONDocument(filterDocuments, "contentType" -> "application/pdf")

      val countPNGFuture: Future[Long] = collection.count(Some(filterPNG))
      val countJPGFuture: Future[Long] = collection.count(Some(filterJPG))
      val countPDFFuture: Future[Long] = collection.count(Some(filterPDF))

      for {
        countPNG <- countPNGFuture
        countJPG <- countJPGFuture
        countPDF <- countPDFFuture
      } yield {
        ContentTypesDTO(
          pngCount = countPNG,
          jpgCount = countJPG,
          pdfCount = countPDF
        )
      }

    })
  }


我只想用一个consult来做这件事,在MongoDB中,我是这样做的:

db.getCollection('myCollection').aggregate([
    {$match: {'metadata.s': {$ne: 'thumbnail'}}},
    {$group: {_id: "$contentType", count: {$sum: 1}} }
])


他们给了我这个:

/* 1 */
{
    "_id" : "image/png",
    "count" : 5.0
}

/* 2 */
{
    "_id" : "application/pdf",
    "count" : 9.0
}

/* 3 */
{
    "_id" : "image/jpeg",
    "count" : 8.0
}


我试着这样做:

def contentTypeStats(implicit ec: ExecutionContext): Future[ContentTypesDTO] = {
    collectionFactory.collection().flatMap(collection => {

      import collection.AggregationFramework._
      val result: Future[Option[BSONDocument]] = collection.aggregatorContext[BSONDocument](
        pipeline = List(
          Match(BSONDocument("metadata.s" -> BSONDocument("$ne" -> "thumbnail"))),
          Group(BSONDocument("_id" -> "$contentType"))("count" -> SumAll)
        )
      ).prepared.cursor.headOption

      result.map {
        case Some(doc) =>
          println(doc.getAsOpt[String]("_id"))//here always return None
          ContentTypesDTO(
            pngCount = doc.getAsOpt[Long]("count").getOrElse(0L),
            jpgCount = doc.getAsOpt[Long]("count").getOrElse(0L),
            pdfCount = doc.getAsOpt[Long]("count").getOrElse(0L)
          )//all have the same number
      }
    })
  }


该方法返回None时,要求_id和计数字段给予随机一些以前的结果(5,8,9),它应该是一种方式来访问特定计数字段的每个_id,应该是image/pngimage/jpegapplication/pdf,但如果我可以得到_id

23c0lvtd

23c0lvtd1#

我的解决方案中有几个问题

val result: Future[Option[BSONDocument]] = collection.aggregatorContext[BSONDocument](
        pipeline = List(
          Match(BSONDocument("metadata.s" -> BSONDocument("$ne" -> "thumbnail"))),
          Group(BSONDocument("_id" -> "$contentType"))("count" -> SumAll)
        )
      ).prepared.cursor.headOption

字符串
这里我将_idMap为BSONDocument,这就是为什么a不能得到_id,所以解决方案是以这种方式Map为BSONString

Group(BSONString("$contentType"))("count" -> SumAll)


Group方法总是用第一个参数创建_id字段。第二个问题是返回结果,这里.prepared.cursor.headOption只从创建的组中返回第一个BSONDocument。要修复的是使用reactivemongo .prepared.cursor.collect[List](-1, Cursor.FailOnError[List[BSONDocument]]())中的Cursor类返回一个BSONDocument的列表,之后还将ContentTypesDTO更改为仅

case class ContentTypesDTO(contentType: String,
                           count: Long)


并使用Map上的result得到一个Seq[ContentTypesDTO]这里的最终解决方案:

def contentTypeStats(implicit ec: ExecutionContext): Future[Seq[ContentTypeDetailsDTO]] = {
    collectionFactory.collection().flatMap(collection => {

      import collection.AggregationFramework.{Group, Match, SumAll}

      val result: Future[List[BSONDocument]] = collection.aggregatorContext[BSONDocument](
        List(
          Match(BSONDocument("metadata.s" -> BSONDocument("$ne" -> "thumbnail"))),
          Group(BSONString("$contentType"))("count" -> SumAll))
      ).prepared.cursor.collect[List](-1, Cursor.FailOnError[List[BSONDocument]]())

      result.map(docList => {
        docList.map {
          doc =>
            ContentTypeDetailsDTO(
              contentType = doc.getAsOpt[String]("_id").getOrElse(""),
              count = doc.getAsOpt[Long]("count").getOrElse(0L)
            )
        }
      })
    })
  }


该方法返回以下内容:

[
  {
    "contentType": "application/pdf",
    "count": 9
  },
  {
    "contentType": "image/svg",
    "count": 1
  },
  {
    "contentType": "image/png",
    "count": 4
  },
  {
    "contentType": "image/jpeg",
    "count": 8
  }
]

相关问题