使用 `$toLong` 在 MongoDB C# 查询中

huangapple go评论66阅读模式
英文:

Using `$toLong` in MongoDB C# Queries

问题

我正在努力将下面的Mongo聚合管道转换为其C#等效项。我试图使用内置的$toLongISODate转换为Unix时间戳。可能有数百万个文档,因此不可行的是使用.ToList().Select(x => ConvertToTimestamp(x.date))

假设我有以下文档:

[
  {
    "value": 100,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 50,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 23,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 199,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  }
]

我有以下工作的聚合查询:

db.collection.aggregate({
  $project: {
    date: {
      $toLong: "$date"
    },
    value: 1,
  }
})

我得到了预期的输出:

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "date": NumberLong(1648269508044),
    "value": 100
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "date": NumberLong(1648269508044),
    "value": 50
  },
  {
    "_id": ObjectId("5a934e000102030405000002"),
    "date": NumberLong(1648269508044),
    "value": 23
  },
  {
    "_id": ObjectId("5a934e000102030405000003"),
    "date": NumberLong(1648269508044),
    "value": 199
  }
]

现在,问题是如何使用C#中的流畅聚合API来执行此操作?

英文:

I'm struggling to convert the below Mongo aggregation pipeline into its C# equivalent. I am trying to convert ISODates to unix timestamps using the built in $toLong. There could be millions of documents, so doing .ToList().Select(x => ConvertToTimestamp(x.date)) is not feasible.

Say I have the following documents:

[
  {
    "value": 100,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 50,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 23,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  },
  {
    "value": 199,
    "date": ISODate("2022-03-26T04:38:28.044Z")
  }
]

I have the following aggregation query that works

db.collection.aggregate({
  $project: {
    date: {
      $toLong: "$date"
    },
    value: 1,
  }
})

And I get the expected output

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "date": NumberLong(1648269508044),
    "value": 100
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "date": NumberLong(1648269508044),
    "value": 50
  },
  {
    "_id": ObjectId("5a934e000102030405000002"),
    "date": NumberLong(1648269508044),
    "value": 23
  },
  {
    "_id": ObjectId("5a934e000102030405000003"),
    "date": NumberLong(1648269508044),
    "value": 199
  }
]

Now, the question is, how to do this with the fluent aggregation API in C#?

答案1

得分: 0

方法1: 将聚合查询作为BsonDocument传递。

var pipelineDefinition = new BsonDocument[]
{
    new BsonDocument
    {
        {
            "$project", new BsonDocument
            {
                { "date", new BsonDocument { { "$toLong", "$date" } } },
                { "value", 1 }
            }
        }
    }
};

List<Model> result = _collection.Aggregate<Model>(pipelineDefinition)
    .ToList();

方法2: 使用BsonSerializer

  1. 实现IBsonSerializer类以将DateTime类型转换为long类型。
public class DateToLongConverter : IBsonSerializer<long>
{
    public Type ValueType => typeof(long);

    public long Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonReader = context.Reader;
        return bsonReader.ReadDateTime();
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, long value)
    {
        var bsonWriter = context.Writer;
        bsonWriter.WriteInt64(value);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        var bsonWriter = context.Writer;
        bsonWriter.WriteInt64((long)value);
    }

    object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonReader = context.Reader;
        return bsonReader.ReadDateTime();
    }
}
  1. Date属性上应用BsonSerializer属性,使用DateToLongConverter
public class Model
{
    public ObjectId Id { get; set; }
    [BsonSerializer(typeof(DateToLongConverter))]
    public long Date { get; set; }
    public int Value { get; set; }
}
  1. Model类注册类映射。
BsonClassMap.RegisterClassMap<Model>(cm =>
{
    cm.AutoMap();

    cm.MapMember(x => x.Date)
        .SetSerializer(new DateToLongConverter());
});
  1. 查询数据:
List<Model> result = (await _collection.FindAsync(new BsonDocument()))
    .ToList();

演示

使用 `$toLong` 在 MongoDB C# 查询中

英文:

Approach 1: Pass aggregation query as BsonDocument.

var pipelineDefinition = new BsonDocument[]
{
    new BsonDocument
    {
        {
            &quot;$project&quot;, new BsonDocument
            {
                { &quot;date&quot;, new BsonDocument { { &quot;$toLong&quot;, &quot;$date&quot; } } },
                { &quot;value&quot;, 1 }
            }
        }
    }
};

List&lt;Model&gt; result = _collection.Aggregate&lt;Model&gt;(pipelineDefinition)
    .ToList();

Approach 2: Work with BsonSerializer.

  1. Implement IBsonSerializer class to convert from DateTime type to long type.
public class DateToLongConverter : IBsonSerializer&lt;long&gt;
{
    public Type ValueType =&gt; typeof(long);

    public long Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonReader = context.Reader;
        return bsonReader.ReadDateTime();
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, long value)
    {
        var bsonWriter = context.Writer;
        bsonWriter.WriteInt64(value);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        var bsonWriter = context.Writer;
        bsonWriter.WriteInt64((long)value);
    }

    object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonReader = context.Reader;
        return bsonReader.ReadDateTime();
    }
}
  1. Apply BsonSerializer attribute with DateToLongConverter to Date property.
public class Model
{
    public ObjectId Id { get; set; }
    [BsonSerializer(typeof(DateToLongConverter))]
    public long Date { get; set; }
    public int Value { get; set; }
}
  1. Register class map for Model class.
BsonClassMap.RegisterClassMap&lt;Model&gt;(cm =&gt;
{
    cm.AutoMap();

    cm.MapMember(x =&gt; x.Date)
        .SetSerializer(new DateToLongConverter());
});
  1. To query data:
List&lt;Model&gt; result = (await _collection.FindAsync(new BsonDocument()))
    .ToList();

> Demo

使用 `$toLong` 在 MongoDB C# 查询中

huangapple
  • 本文由 发表于 2023年3月7日 15:30:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定