反应式 mongo 组元素并计算它们

问题描述 投票:0回答:1

我有一个 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
        )
      }

    })
  }

我只想通过一次咨询来完成此操作,在 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/png
image/jpeg
application/pdf
但如果我能得到
_id

该怎么办
mongodb scala mongodb-query reactivemongo
1个回答
0
投票

我的解决方案中存在一些问题

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

这里我将

_id
映射为
BSONDocument
,这就是为什么a无法获得
_id
,所以解决方案就是以这种方式映射为
BSONString

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

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

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

并使用

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
  }
]
© www.soinside.com 2019 - 2024. All rights reserved.