MongoDB.Driver
//
// 摘要:
// 【异步】Bulk批量更新 (存在时更新,否则插入记录)
//
// 参数:
// items:
// 更新记录
//
// filterFields:
// 用于判断记录是否存在的字段名
//
// onlyInsertFields:
// 插入时才入库的字段名,即更新时忽略的字段名
//
// collName:
// 指定集合名,不指定则用默认集合名
//
// isMany:
// true,更新符合条件的所有记录; false,只更新符合条件的第一条
//
// isUpsert:
// true为插入和更新,不存在则插入;false为仅更新记录不插入
//
// incrementFields:
// 在原来字段上增加值的字段名
//
// 返回结果:
// 结果
public async Task<BulkWriteResult<TModel>> BatchUpdateAsync(IEnumerable<TModel> items, List<string> filterFields, List<string> onlyInsertFields, string collName = null, bool isMany = false, bool isUpsert = true, List<string> incrementFields = null)
{
IMongoCollection<TModel> collection = GetCollection(collName);
IEnumerable<WriteModel<TModel>> requests = BuiderUpdateModel(items, filterFields, onlyInsertFields, incrementFields, isMany, isUpsert);
return await collection.BulkWriteAsync(requests);
}
private UpdateOneModel<TModel> BuiderUpdateDefinition(TModel d)
{
if (ObjectId.Empty.Equals(d.ID))
{
d.ID = ObjectId.GenerateNewId();
}
UpdateDefinitionBuilder<TModel> update = Builders<TModel>.Update;
List<UpdateDefinition<TModel>> list = new List<UpdateDefinition<TModel>>();
PropertyInfo[] properties = typeof(TModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in properties)
{
if (propertyInfo.Name != "ID")
{
list.Add(update.Set(propertyInfo.Name, propertyInfo.GetValue(d)));
}
}
UpdateDefinition<TModel> update2 = update.Combine(list).SetOnInsert((TModel x) => x.ID, d.ID);
return new UpdateOneModel<TModel>(Builders<TModel>.Filter.Eq((TModel x) => x.ID, d.ID), update2)
{
IsUpsert = true
};
}
private IEnumerable<WriteModel<TModel>> BuiderUpdateModel(IEnumerable<TModel> items, List<string> filterFields, List<string> onlyInsertFields, List<string> incrementFields, bool isMany, bool isUpsert)
{
if (filterFields == null)
{
filterFields = new List<string>();
}
if (onlyInsertFields == null)
{
onlyInsertFields = new List<string>();
}
if (incrementFields == null)
{
incrementFields = new List<string>();
}
if (isMany)
{
return items.Select(delegate (TModel d)
{
if (ObjectId.Empty.Equals(d.ID))
{
d.ID = ObjectId.GenerateNewId();
}
UpdateDefinitionBuilder<TModel> update3 = Builders<TModel>.Update;
FilterDefinitionBuilder<TModel> filter2 = Builders<TModel>.Filter;
List<UpdateDefinition<TModel>> list3 = new List<UpdateDefinition<TModel>>();
List<FilterDefinition<TModel>> list4 = new List<FilterDefinition<TModel>>();
PropertyInfo[] properties2 = typeof(TModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo2 in properties2)
{
if (propertyInfo2.Name != "ID" && !onlyInsertFields.Contains(propertyInfo2.Name))
{
if (incrementFields.Contains(propertyInfo2.Name))
{
list3.Add(update3.Inc(propertyInfo2.Name, propertyInfo2.GetValue(d)));
}
else
{
list3.Add(update3.Set(propertyInfo2.Name, propertyInfo2.GetValue(d)));
}
}
else
{
list3.Add(update3.SetOnInsert(propertyInfo2.Name, propertyInfo2.GetValue(d)));
}
if (filterFields.Contains(propertyInfo2.Name))
{
list4.Add(filter2.Eq(propertyInfo2.Name, propertyInfo2.GetValue(d)));
}
}
if (list4.Count == 0)
{
list4.Add(filter2.Eq((TModel x) => x.ID, d.ID));
}
UpdateDefinition<TModel> update4 = update3.Combine(list3);
return new UpdateManyModel<TModel>(filter2.And(list4), update4)
{
IsUpsert = isUpsert
};
});
}
return items.Select(delegate (TModel d)
{
if (ObjectId.Empty.Equals(d.ID))
{
d.ID = ObjectId.GenerateNewId();
}
UpdateDefinitionBuilder<TModel> update = Builders<TModel>.Update;
FilterDefinitionBuilder<TModel> filter = Builders<TModel>.Filter;
List<UpdateDefinition<TModel>> list = new List<UpdateDefinition<TModel>>();
List<FilterDefinition<TModel>> list2 = new List<FilterDefinition<TModel>>();
PropertyInfo[] properties = typeof(TModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in properties)
{
if (propertyInfo.Name != "ID" && !onlyInsertFields.Contains(propertyInfo.Name))
{
if (incrementFields.Contains(propertyInfo.Name))
{
list.Add(update.Inc(propertyInfo.Name, propertyInfo.GetValue(d)));
}
else
{
list.Add(update.Set(propertyInfo.Name, propertyInfo.GetValue(d)));
}
}
else
{
list.Add(update.SetOnInsert(propertyInfo.Name, propertyInfo.GetValue(d)));
}
if (filterFields.Contains(propertyInfo.Name))
{
list2.Add(filter.Eq(propertyInfo.Name, propertyInfo.GetValue(d)));
}
}
if (list2.Count == 0)
{
list2.Add(filter.Eq((TModel x) => x.ID, d.ID));
}
UpdateDefinition<TModel> update2 = update.Combine(list);
return new UpdateOneModel<TModel>(filter.And(list2), update2)
{
IsUpsert = isUpsert
};
});
}
修改时报错:A bulk write operation resulted in one or more errors.
译:分片集合上的upstart必须包含分片密钥并具有简单的排序规则。
出现在批量修改的时候,方法存在修改,不存在新增,设置的依据是mongdb的唯一键_id,应该改为mongdb里的分片键(唯一键),分片键基本和唯一键相同