【问题标题】:Mongo's distinct value count for two fields in JavaMongo对Java中两个字段的不同值计数
【发布时间】:2014-01-30 09:39:00
【问题描述】:

我正在使用 java 连接到 MongoDB。 我想获取和计算两个字段的不同值,即 requestId 和 telNum。我用谷歌搜索,但没有找到如何获取两个字段的不同值。

【问题讨论】:

标签: java mongodb aggregation-framework


【解决方案1】:

MongoDB 有一个Aggregation Framework 和管道,有点类似于 SQL“GROUP BY”,但这些阶段可以做更高级的工作。我们将展示一个三阶段示例,以获取多次出现的不同组合的计数。

考虑到您的意思是文档中 requestId 和 telNum 的相同值的不同出现,并将其视为相应的 SQL

SELECT requestId, telNum, count(*) as counter
from collection
GROUP BY requestId, telNum

mongo shell 位是对结合两个值的 _id 键group。因此:

db.collection.aggregate([
    {$group: { _id: { requestId: "$requestId", telNum: "$telNum" }, count: {$sum: 1} } }
])

Java 中的要点:

// Construct our _id to group on
DBObject fields = new BasicDBObject( "requestId", "$requestId" );
fields.put( "telNum", "$telNum" );

// Contruct group element
DBObject groupFields = new BasicDBObject( "_id", fields );
groupFields.put( "count", new BasicDBObject( "$sum", 1 ) );
DBObject group = new BasicDBObject( "$group", groupFields );



// Run aggregation
AggregationOutput output = collection.aggregate( group );

所以这里的输出会匹配上面的 SQL。

更进一步,让我们考虑完整的 SQL 来为我们提供不止一次的不同计数:

SELECT count(*) 
FROM ( 
  SELECT requestId, telNum, count(*) as counter
  FROM collection
  GROUP BY requestId, telNum
) a
WHERE a.counter > 1

所以我们可以修改代码,将更多阶段添加到聚合管道中,再次添加到 $match (WHERE/HAVING) 和 $group (GROUP BY):

// Construct a match on things with a count of more than 1
DBObject greaterThan = new BasicDBObject( "$gt", 1 );
DBObject matchFields = new BasicDBObject( "count", greaterTen );
DBObject match = new BasicDBObject( "$match", matchFields );

// Count the documents that match
DBObject newGroupFields = new BasicDBObject( "_id", null );
newGroupFields.put( "count", new BasicDBOject( "$sum", 1 ) );
DBObject group2 = new BasicDBObject( "$group", newGroupFields );

// Run aggregation
AggregationOutput output = collection.aggregate( group, match, group2 );

所以这链中的三个阶段

  1. 分组获取字段不同值的计数
  2. 过滤掉只有 1 个不同值的文档,所以只留下重复的文档
  3. 从过滤器的结果中计算出不同的对

聚合允许您将这样的各个阶段“链接”在一起以获得结果。它非常适合这种工作,值得注意的是它比使用Map-Reduce 快得多,尽管它仍然有它的用途。

根据需要编辑和播放。

还有一个有用的例子可以关注here

【讨论】:

  • 工作正常,但我想计算这个输出。我应该使用迭代器吗?
  • 之前没看到评论。更新后的答案显示将阶段进一步减少到一个计数。
  • 我不了解聚合。请帮我再添加一个约束,即日期应该大于某事(“2014-05-06”)
【解决方案2】:
    import com.mongodb.MongoClient;
    import com.mongodb.MongoException;
    import com.mongodb.WriteConcern;
    import com.mongodb.DB;
    import com.mongodb.DBCollection;
    import com.mongodb.BasicDBObject;
    import com.mongodb.DBObject;
    import com.mongodb.DBCursor;
    import com.mongodb.ServerAddress;

    import java.util.Arrays;

    // To directly connect to a single MongoDB server (note that this will not auto-discover the primary even
    // if it's a member of a replica set:
    MongoClient mongoClient = new MongoClient();

    DB db = mongoClient.getDB( "mydb" );
    AggregationOutput output =db.CollectionName.mapReduce(
    function(){ emit(this.id, this.name);},
    function(key, value) { return Array.sum(1)},
    {
     query: {status: "A"},
     out: "uniq_id_name"
    }
    );
System.out.println(output);

【讨论】:

    【解决方案3】:

    试试这个:

    db.collection.aggregate( 
        { 
            $group: { 
                _id : "$the_field_to_be_grouped",  // enter the field you want to group by
                totalRequestId : { $sum : "$requestId" }, 
                totaltelNum: { $sum : "$telNum" }  
            } 
        }
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-25
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多