Skip to content

Commit

Permalink
feat: MongoDB实体Id转换支持子对象及集合成员 (#562)
Browse files Browse the repository at this point in the history
  • Loading branch information
joesdu authored Oct 2, 2024
2 parents fcd6de8 + e6f268b commit b788025
Show file tree
Hide file tree
Showing 4 changed files with 434 additions and 3 deletions.
273 changes: 273 additions & 0 deletions sample/WebApi.Test.Unit/Controllers/MongoArrayController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
using EasilyNET.Core.Enums;
using EasilyNET.Core.Misc;
using EasilyNET.Mongo.Core;
using EasilyNET.WebCore.Swagger.Attributes;
using Microsoft.AspNetCore.Mvc;
using MongoCRUD.Models;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;

namespace WebApi.Test.Unit.Controllers;

/// <summary>
/// Mongo的数组对象操作
/// </summary>
/// <param name="db"></param>
[Route("api/[controller]"), ApiController, ApiGroup("MongoTest", "v1", "MongoDB一些测试")]
public class MongoArrayController(DbContext db) : ControllerBase
{
private readonly FilterDefinitionBuilder<FamilyInfo> _bf = Builders<FamilyInfo>.Filter;
private readonly UpdateDefinitionBuilder<FamilyInfo> _bu = Builders<FamilyInfo>.Update;

/// <summary>
/// 初始化数据
/// </summary>
/// <returns></returns>
[HttpPost("Init")]
public async Task<List<FamilyInfo>> Init()
{
var obj = new List<FamilyInfo>
{
new()
{
Name = "野比家",
Members =
[
new()
{
Index = 0,
Name = "野比大助",
Age = 40,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1943-01-24", "yyyy-MM-dd")
},
new()
{
Index = 1,
Name = "野比玉子",
Age = 34,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1941-09-30", "yyyy-MM-dd")
},
new()
{
Index = 2,
Name = "野比大雄",
Age = 10,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1964-08-07", "yyyy-MM-dd")
},
new()
{
Index = 3,
Name = "哆啦A梦",
Age = 1,
Gender = EGender.,
Birthday = DateOnly.ParseExact("2112-09-03", "yyyy-MM-dd")
}
]
},
new()
{
Name = "蜡笔小新",
Members =
[
new()
{
Index = 0,
Name = "野原广志",
Age = 35,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1963-09-27", "yyyy-MM-dd")
},
new()
{
Index = 1,
Name = "野原美冴",
Age = 29,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1969-10-10", "yyyy-MM-dd")
},
new()
{
Index = 2,
Name = "野原新之助",
Age = 5,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1994-07-22", "yyyy-MM-dd")
},
new()
{
Index = 3,
Name = "野原向日葵",
Age = 1,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1998-09-27", "yyyy-MM-dd")
}
]
},
new()
{
Name = "猫和老鼠",
Members =
[
new()
{
Index = 0,
Name = "Tom",
Age = 84,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1940-02-10", "yyyy-MM-dd")
},
new()
{
Index = 1,
Name = "Jerry",
Age = 84,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1940-02-10", "yyyy-MM-dd")
},
new()
{
Index = 2,
Name = "Spike",
Age = 82,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1942-04-18", "yyyy-MM-dd")
},
new()
{
Index = 3,
Name = "Tyke",
Age = 70,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1953-09-03", "yyyy-MM-dd")
},
new()
{
Index = 4,
Name = "Nibbles",
Age = 77,
Gender = EGender.,
Birthday = DateOnly.ParseExact("1946-05-08", "yyyy-MM-dd")
}
]
}
};
await db.FamilyInfo.InsertManyAsync(obj);
return obj;
}

/// <summary>
/// 添加一个元素
/// </summary>
/// <returns></returns>
[HttpPost("Create")]
public async Task<Person> AddOneElement()
{
var dorami = new Person
{
Id = ObjectId.GenerateNewId().ToString(),
Index = 4,
Name = "哆啦美",
Age = 1,
Gender = EGender.,
Birthday = DateOnly.ParseExact("2114-12-02", "yyyy-MM-dd")
};
await db.FamilyInfo.UpdateOneAsync(c => c.Name == "野比家", _bu.Push(c => c.Members, dorami));
return dorami;
}

/// <summary>
/// 更新一个元素
/// </summary>
/// <returns></returns>
[HttpPut("UpdateOne")]
public async Task UpdateOneElement()
{
// 这里我们举得例子是将哆啦美的名字变更为日文名字.
// 这里我们假设查询参数同样是通过参数传入的,所以我们写出了如下代码.
//await db.FamilyInfo.UpdateOneAsync(c => (c.Name == "野比家") & c.Members.Any(s => s.Index == 4),
// _bu.Set(c => c.Members.FirstMatchingElement().Name, "ドラミ"));
//await db.FamilyInfo.UpdateOneAsync(_bf.Eq(c => c.Name, "蜡笔小新"),
// _bu.Inc(c => c.Members.AllMatchingElements("ele").Age, 100), new()
// {
// ArrayFilters =
// [
// //new BsonDocumentArrayFilterDefinition<BsonDocument>(new($"ele.{nameof(Person.Gender).ToLowerCamelCase()}", EGender.女.ToString()))
// new BsonDocumentArrayFilterDefinition<Person>(new($"ele.{nameof(Person.Age).ToLowerCamelCase()}", new BsonDocument("$lt", 1000)))
// ]
// });
await db.FamilyInfo.UpdateOneAsync(_bf.Eq(c => c.Name, "蜡笔小新"),
_bu.Inc(c => c.Members.AllMatchingElements("ele").Age, 100), new()
{
ArrayFilters =
[
//new BsonDocumentArrayFilterDefinition<BsonDocument>(new($"ele.{nameof(Person.Gender).ToLowerCamelCase()}", EGender.女.ToString()))
new JsonArrayFilterDefinition<BsonDocument>(new($$"""
{
"ele.{{nameof(Person.Age).ToLowerCamelCase()}}" : {
"$lt" : {{1000}}
}
}
"""))
]
});
}

/// <summary>
/// 删除一个元素
/// </summary>
/// <returns></returns>
[HttpDelete("DeleteOne")]
public async Task DeleteOneElement()
{
await db.FamilyInfo.UpdateOneAsync(c => c.Name == "野比家", _bu.PullFilter(c => c.Members, f => f.Index == 4));
}

/// <summary>
/// 获取一个元素
/// </summary>
/// <returns></returns>
[HttpGet("OneElement")]
public async Task<Person> GetOneElement()
{
//var sql = _db.FamilyInfo.Find(c => c.Name == "野比家")
// .Project(c => c.Members.First()).ToString();
return await db.FamilyInfo.Find(c => c.Name == "野比家").Project(c => c.Members.First()).SingleOrDefaultAsync();
//return await _db.FamilyInfo.Find(c => c.Name == "野比家")
// .Project(c => c.Members.Find(s => s.Name == "哆啦A梦")).SingleOrDefaultAsync();
}

/// <summary>
/// 获取所有元素
/// </summary>
/// <returns></returns>
[HttpGet("AllElement")]
public async Task<IEnumerable<Person>> GetAllElement()
{
return await db.FamilyInfo.Find(c => c.Name == "野比家").Project(c => c.Members).SingleOrDefaultAsync();
}

/// <summary>
/// 对数组对象进行行列转换
/// </summary>
/// <returns></returns>
[HttpGet("Unwind")]
public async Task<dynamic> GetUnwind()
{
// Project中的UnwindObj我们往往使用子类,这样可以将一些不必要的数据屏蔽或者丢弃
var query = db.FamilyInfo.Aggregate().Match(c => c.Name == "野比家")
.Project(c => new UnwindObj<List<Person>>
{
Obj = c.Members,
Count = c.Members.Count
})
.Unwind(c => c.Obj, new AggregateUnwindOptions<UnwindObj<Person>> { IncludeArrayIndex = "Index" });
//var sql = query.ToString();
var total = await query.Count().FirstOrDefaultAsync();
var list = await query.ToListAsync();
return new Tuple<long?, List<UnwindObj<Person>>>(total.Count, list);
}
}
6 changes: 6 additions & 0 deletions sample/WebApi.Test.Unit/DbContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EasilyNET.Mongo.Core;
using MongoCRUD.Models;
using MongoDB.Driver;

// ReSharper disable ClassNeverInstantiated.Global
Expand All @@ -17,4 +18,9 @@ public sealed class DbContext : MongoContext
/// MongoTest2
/// </summary>
public IMongoCollection<MongoTest2> Test2 => GetCollection<MongoTest2>("mongo.test2");

/// <summary>
/// ¼ÒÍ¥ÐÅÏ¢
/// </summary>
public IMongoCollection<FamilyInfo> FamilyInfo => Database.GetCollection<FamilyInfo>("family.info");
}
60 changes: 60 additions & 0 deletions sample/WebApi.Test.Unit/Domain/FamilyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// ReSharper disable ClassNeverInstantiated.Global

using EasilyNET.Core.Enums;

namespace MongoCRUD.Models;

public class FamilyInfo

Check warning on line 7 in sample/WebApi.Test.Unit/Domain/FamilyInfo.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'FamilyInfo'

Check warning on line 7 in sample/WebApi.Test.Unit/Domain/FamilyInfo.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'FamilyInfo'
{
/// <summary>
/// 数据ID
/// </summary>
public string Id { get; set; } = string.Empty;

/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = string.Empty;

/// <summary>
/// 家庭成员
/// </summary>
public List<Person> Members { get; set; } = [];
}

/// <summary>
/// 人
/// </summary>
// ReSharper disable once ClassNeverInstantiated.Global
public class Person
{
/// <summary>
/// 数据ID
/// </summary>
public string Id { get; set; } = string.Empty;

/// <summary>
/// 和例子中的数据结构同步
/// </summary>
public int Index { get; set; }

/// <summary>
/// Name
/// </summary>
public string Name { get; set; } = string.Empty;

/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }

/// <summary>
/// 性别
/// </summary>
public EGender Gender { get; set; } = EGender.;

/// <summary>
/// 临时决定,使用.Net 6新增类型保存生日,同时让例子变得丰富,明白如何将MongoDB不支持的数据类型序列化
/// </summary>
public DateOnly Birthday { get; set; }
}
Loading

0 comments on commit b788025

Please sign in to comment.