Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,973 @@
|
||||
using adas_core.Application.Repositories.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.DTO;
|
||||
using adas_core.Domain.Models.Filter;
|
||||
using adas_core.Domain.Models.Masters;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
using Serilog;
|
||||
using System.Text.RegularExpressions;
|
||||
using MongoUtils = adas_core.Infrastructure.Utils.MongoUtils;
|
||||
|
||||
namespace adas_core.Infrastructure.Repositories;
|
||||
|
||||
public class PatientRepository : MongoRepository<Patient>, IPatientRepository
|
||||
{
|
||||
private readonly ApiSettings _apiSettings;
|
||||
|
||||
public PatientRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
|
||||
{
|
||||
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
|
||||
_apiSettings = apiSettings.Value;
|
||||
} //For testing
|
||||
|
||||
// public PatientRepository(IOptions<ApiSettings> apiSettings, IOptions<DatabaseSettings> dbSetting) :
|
||||
// base(dbSetting)
|
||||
// {
|
||||
// if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
|
||||
// _apiSettings = apiSettings.Value;
|
||||
// }
|
||||
|
||||
public override string GetCollectionName()
|
||||
{
|
||||
return _apiSettings.Patients ?? "patients";
|
||||
}
|
||||
|
||||
public async Task<Patient?> FindById(ObjectId id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq(p => p.Id, id);
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Error searching patient by id: {id}. Exception: {ex}", id, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Patient?> FindByPointOfCareId(ObjectId id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq(p => p.PointOfCareId, id);
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Error searching patient by id: {id}. Exception: {ex}", id, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Patient> FindByUnitAndPocId(ObjectId unit, ObjectId pointOfCare)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.And(
|
||||
Builders<Patient>.Filter.Eq(p => p.PointOfCareId, pointOfCare),
|
||||
Builders<Patient>.Filter.Eq(p => p.UnitId, unit)
|
||||
);
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Error searching patient by unitId: {unitid} pointOfCareid: {id}. Exception: {ex}", unit,
|
||||
pointOfCare, ex);
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
|
||||
//Deprecated
|
||||
public async Task<Patient?> FindByLocation(PatientLocation? location)
|
||||
{
|
||||
if (location == null)
|
||||
return null;
|
||||
// Primero encontrar la unidad
|
||||
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var filter = filterBuilder.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(location.UnitName) && !string.IsNullOrEmpty(location.Bed))
|
||||
filter = filterBuilder.And(
|
||||
filterBuilder.Eq(p => p.UnitString, location.UnitName),
|
||||
filterBuilder.Eq(p => p.Bed, location.Bed)
|
||||
);
|
||||
else if (!string.IsNullOrEmpty(location.Bed)) filter = filterBuilder.Eq(p => p.Bed, location.Bed);
|
||||
|
||||
var result = await Collection.Find(filter).Limit(1).FirstOrDefaultAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public override async Task InsertOneAsync(Patient patient)
|
||||
{
|
||||
try
|
||||
{
|
||||
patient.CreationDate = DateTime.UtcNow;
|
||||
await base.InsertOneAsync(patient);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
|
||||
var patientAux = await FindByLocation(patient.Location);
|
||||
if (patientAux != null && patientAux.PatientNumber == patient.PatientNumber)
|
||||
{
|
||||
Log.Warning("Exception trying to insert an existing patient: {patient}. Exception {e}", patient, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Exception trying to insert patient: {patient}. Exception {e}", patient, e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Update(Patient patient)
|
||||
{
|
||||
patient.UpdateDate = DateTime.UtcNow;
|
||||
await UpdateOneAsync(patient.Id, patient);
|
||||
}
|
||||
|
||||
public async Task Delete(ObjectId id)
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq(x => x.Id, id);
|
||||
await Collection.DeleteOneAsync(filter, null);
|
||||
}
|
||||
|
||||
public async Task UpdateLocation(ObjectId id, PatientLocation location)
|
||||
{
|
||||
var patient = await FindById(id);
|
||||
if (patient == null)
|
||||
{
|
||||
Log.Warning("Patient not found for updating location: {id}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
patient.UpdateDate = DateTime.UtcNow;
|
||||
patient.Location = location;
|
||||
await UpdateOneAsync(patient.Id, patient);
|
||||
/*var filterBuilder = Builders<Patient>.Filter;
|
||||
var filter = filterBuilder.Eq(p => p.Id, id);
|
||||
|
||||
var update = Builders<Patient>.Update
|
||||
.Set(p => p.Bed, location?.Bed)
|
||||
.Set(p => p.UnitString, location?.UnitName)
|
||||
.Set(p => p.UpdateDate, DateTime.UtcNow)
|
||||
.AddToSet(p => p.HistoricalLocations, new KeyValuePair<string, PatientLocation>(DateTime.UtcNow.ToString("o"), location));
|
||||
|
||||
var result = await Collection.UpdateOneAsync(filter, update);
|
||||
|
||||
Log.Debug("Update location result: {result}", result);*/
|
||||
}
|
||||
|
||||
public async Task UpdateLocation(ObjectId id, ObjectId location)
|
||||
{
|
||||
var patient = await FindById(id);
|
||||
if (patient == null)
|
||||
{
|
||||
Log.Warning("Patient not found for updating location: {id}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
patient.UpdateDate = DateTime.UtcNow;
|
||||
patient.PointOfCareId = location;
|
||||
await UpdateOneAsync(patient.Id, patient);
|
||||
}
|
||||
|
||||
public async Task UpdateAttendingDoctor(ObjectId id, Person attendingDoctor)
|
||||
{
|
||||
var update = Builders<Patient>.Update
|
||||
.Set(p => p.AttendingDoctor, attendingDoctor)
|
||||
.Set(p => p.UpdateDate, DateTime.UtcNow);
|
||||
|
||||
await Collection.UpdateOneAsync(p => p.Id == id, update);
|
||||
}
|
||||
|
||||
public async Task UpdatePatientData(ObjectId id, string patientNumber, Person data, bool updatePatientNumber = true)
|
||||
{
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var updateBuilder = Builders<Patient>.Update.Set(p => p.Person, data).Set(p => p.UpdateDate, DateTime.UtcNow);
|
||||
|
||||
var filter = filterBuilder.Eq(p => p.Id, id);
|
||||
var update = updateBuilder;
|
||||
|
||||
if (updatePatientNumber) update = update.Set(p => p.PatientNumber, patientNumber);
|
||||
|
||||
await Collection.UpdateOneAsync(filter, update);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Patient?> FindByPatientNumber(string patientNumber)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(patientNumber)) return null;
|
||||
|
||||
//Último paciente admitido
|
||||
var patient = await Collection.Find(Builders<Patient>.Filter.And(
|
||||
Builders<Patient>.Filter.Eq(p => p.DisTime, null),
|
||||
Builders<Patient>.Filter.Eq(p => p.PatientNumber, patientNumber)
|
||||
))
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.AdmTime))
|
||||
.Limit(1)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
|
||||
//Último con fecha de alta más reciente
|
||||
patient ??= await Collection.Find(Builders<Patient>.Filter.And(
|
||||
Builders<Patient>.Filter.Ne(p => p.DisTime, null),
|
||||
Builders<Patient>.Filter.Eq(p => p.PatientNumber, patientNumber)
|
||||
))
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.DisTime))
|
||||
.Limit(1)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return patient;
|
||||
}
|
||||
|
||||
public async Task<Patient?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(patientNumber)) return null;
|
||||
|
||||
// Paciente ubicado en un PoC pero en diferente unidad
|
||||
var patient = await Collection.Find(Builders<Patient>.Filter.And(
|
||||
Builders<Patient>.Filter.Eq(p => p.PatientNumber, patientNumber),
|
||||
Builders<Patient>.Filter.Ne(p => p.UnitId, unitId)
|
||||
)).ToListAsync();
|
||||
// Si hay mas de una coincidencia devolvemos null por que puede no estar completo el patientNumber
|
||||
return patient.Count > 1 ? null : patient.FirstOrDefault();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
"Error Search By Patient Number And Distinct Unit on patient repository patientNumber: {patientNumber}, unitId: {unitId}, Excepción: {e}",
|
||||
patientNumber, unitId, e.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindAllPatientWithFinishedProcedures(int archiveProcedureEndDateAfterMinutes)
|
||||
{
|
||||
var currentDateTime = DateTime.UtcNow;
|
||||
|
||||
// Filtro para documentos que contienen al menos un procedimiento con opción "procedure"
|
||||
var filter = Builders<Patient>.Filter.ElemMatch(
|
||||
x => x.Procedures,
|
||||
procedure =>
|
||||
//procedure.OptionType == "procedure" &&
|
||||
procedure.EndDate.HasValue
|
||||
);
|
||||
|
||||
// Ejecutar la consulta inicial y traer los documentos
|
||||
var patientsWithProcedures = await Collection.Find(filter).ToListAsync();
|
||||
|
||||
// Aplicar el filtro adicional en memoria
|
||||
var patientsWithFinishedProcedures = patientsWithProcedures.Where(patient =>
|
||||
patient.Procedures != null &&
|
||||
patient.Procedures.Any(procedure =>
|
||||
procedure is
|
||||
{
|
||||
//OptionType: "procedure",
|
||||
EndDate: not null
|
||||
} &&
|
||||
procedure.EndDate.Value.AddMinutes(archiveProcedureEndDateAfterMinutes) < currentDateTime
|
||||
)
|
||||
).ToList();
|
||||
|
||||
return patientsWithFinishedProcedures;
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindAllPatientWithFinishedTests(int archiveTestEndDateAfterMinutes)
|
||||
{
|
||||
var currentDateTime = DateTime.UtcNow;
|
||||
|
||||
// Filtro para documentos que contienen al menos un procedimiento con opción "procedure"
|
||||
var filter = Builders<Patient>.Filter.ElemMatch(
|
||||
x => x.Tests,
|
||||
procedure => //procedure.OptionType == "test" &&
|
||||
procedure.EndDate.HasValue
|
||||
);
|
||||
|
||||
// Ejecutar la consulta inicial y traer los documentos
|
||||
var patientsWithTests = await Collection.Find(filter).ToListAsync();
|
||||
|
||||
// Aplicar el filtro adicional en memoria
|
||||
var patientsWithFinishedTests = patientsWithTests.Where(patient =>
|
||||
patient.Tests != null &&
|
||||
patient.Tests.Any(procedure =>
|
||||
procedure is
|
||||
{
|
||||
//OptionType: "test",
|
||||
EndDate: not null
|
||||
} &&
|
||||
procedure.EndDate.Value.AddMinutes(archiveTestEndDateAfterMinutes) < currentDateTime
|
||||
)
|
||||
).ToList();
|
||||
|
||||
return patientsWithFinishedTests;
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindAllPatientWithFinishedTreatment(int archiveTreatmentEndDateAfterMinutes)
|
||||
{
|
||||
var currentDateTime = DateTime.UtcNow;
|
||||
|
||||
// Filtro para documentos que contienen al menos un procedimiento con opción "procedure"
|
||||
var filter = Builders<Patient>.Filter.ElemMatch(
|
||||
x => x.Treatment,
|
||||
treatment => treatment.EndDate.HasValue
|
||||
);
|
||||
|
||||
// Ejecutar la consulta inicial y traer los documentos
|
||||
var patientsWithTreatment = await Collection.Find(filter).ToListAsync();
|
||||
|
||||
// Aplicar el filtro adicional en memoria
|
||||
var patientsWithFinishedTreatments = patientsWithTreatment.Where(patient =>
|
||||
patient.Treatment != null &&
|
||||
patient.Treatment.Any(treatment =>
|
||||
treatment.EndDate.HasValue &&
|
||||
treatment.EndDate.Value.AddMinutes(archiveTreatmentEndDateAfterMinutes) < currentDateTime
|
||||
)
|
||||
).ToList();
|
||||
|
||||
return patientsWithFinishedTreatments;
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
|
||||
string typeName)
|
||||
{
|
||||
var isParsed = Enum.TryParse<MasterListType>(typeName, out var parsedTypeName);
|
||||
if (isParsed)
|
||||
{
|
||||
// Tener en cuenta los datos auxiliares ya que pueden ser texto libre o asignarse el establecido en la lista
|
||||
// originAux / diagnosisAux modificar en caso de ser el mismo que el padre
|
||||
// Notificar a todos los fronts con el nuevo valor de cada paciente por el id de los poc's afectados(?)
|
||||
var filterUnit = Builders<Patient>.Filter.In("unitId", unitIds);
|
||||
switch (parsedTypeName)
|
||||
{
|
||||
case MasterListType.DiagnosisList:
|
||||
|
||||
var diagnosisFilter = Builders<Patient>.Filter.Eq(
|
||||
"diagnosis.name", opt.OldOption?.Name
|
||||
);
|
||||
var filterUpdateDiagnosis = Builders<Patient>.Filter.And(filterUnit, diagnosisFilter);
|
||||
var updateDiagnosis = Builders<Patient>.Update
|
||||
.Set("diagnosis.name", opt.UpdatedOption?.Name)
|
||||
.Set("diagnosis.description", opt.UpdatedOption?.Description);
|
||||
await Collection.UpdateManyAsync(filterUpdateDiagnosis, updateDiagnosis);
|
||||
|
||||
await Collection.UpdateManyAsync(Builders<Patient>.Filter.And(filterUnit,
|
||||
Builders<Patient>.Filter.Eq(
|
||||
"diagnosisAux", opt.OldOption?.Name
|
||||
)), Builders<Patient>.Update
|
||||
.Set("diagnosisAux", opt.UpdatedOption?.Name));
|
||||
|
||||
// Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux)
|
||||
var diagnosisFilterToReturn =
|
||||
Builders<Patient>.Filter.Eq("diagnosis.name", opt.UpdatedOption?.Name);
|
||||
var diagnosisAuxFilterToReturn =
|
||||
Builders<Patient>.Filter.Eq("diagnosisAux", opt.UpdatedOption?.Name);
|
||||
var filterToReturn = Builders<Patient>.Filter.And(
|
||||
filterUnit,
|
||||
Builders<Patient>.Filter.Or(diagnosisFilterToReturn, diagnosisAuxFilterToReturn)
|
||||
);
|
||||
|
||||
// Devolver los documentos actualizados
|
||||
var updatedDocuments = await Collection.Find(filterToReturn).ToListAsync();
|
||||
return updatedDocuments;
|
||||
case MasterListType.DoctorList:
|
||||
// Filtro para encontrar el elemento en el array `doctors` que coincida con el nombre
|
||||
var doctorFilter = Builders<Patient>.Filter.ElemMatch(
|
||||
"doctors",
|
||||
Builders<Patient>.Filter.Eq("name", opt.OldOption?.Name)
|
||||
);
|
||||
var filterUpdateDoctor = Builders<Patient>.Filter.And(filterUnit, doctorFilter);
|
||||
|
||||
// Actualizar todos los elementos de la lista `doctors` que coincidan
|
||||
var updateDoctor = Builders<Patient>.Update.Set(
|
||||
"doctors.$[nameElem].name", opt.UpdatedOption?.Name
|
||||
);
|
||||
|
||||
// Definir filtros únicos para cada campo utilizado
|
||||
var arrayFilters = new List<ArrayFilterDefinition>
|
||||
{
|
||||
new BsonDocumentArrayFilterDefinition<BsonDocument>(
|
||||
new BsonDocument("nameElem.name", opt.OldOption?.Name))
|
||||
};
|
||||
|
||||
// Agregar filtro para `optionType` solo si es necesario
|
||||
if (!string.IsNullOrEmpty(opt.OldOption?.OptionType))
|
||||
{
|
||||
updateDoctor = updateDoctor.Set(
|
||||
"doctors.$[typeElem].optionType", opt.UpdatedOption?.OptionType
|
||||
);
|
||||
|
||||
arrayFilters.Add(
|
||||
new BsonDocumentArrayFilterDefinition<BsonDocument>(
|
||||
new BsonDocument("typeElem.optionType", opt.OldOption.OptionType)));
|
||||
}
|
||||
|
||||
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
|
||||
|
||||
// Ejecutar la actualización
|
||||
await Collection.UpdateManyAsync(filterUpdateDoctor, updateDoctor, updateOptions);
|
||||
|
||||
// Devolver los documentos actualizados
|
||||
var doctorFilterToReturn = Builders<Patient>.Filter.ElemMatch(
|
||||
"doctors",
|
||||
Builders<Patient>.Filter.Eq("name", opt.UpdatedOption?.Name)
|
||||
);
|
||||
|
||||
var filterToReturnDoctor = Builders<Patient>.Filter.And(filterUnit, doctorFilterToReturn);
|
||||
|
||||
var updatedDoctorDocuments = await Collection.Find(filterToReturnDoctor).ToListAsync();
|
||||
|
||||
return updatedDoctorDocuments;
|
||||
case MasterListType.InsulationList:
|
||||
break;
|
||||
case MasterListType.OriginList:
|
||||
var originFilter = Builders<Patient>.Filter.Eq(
|
||||
"origin.name", opt.OldOption?.Name
|
||||
);
|
||||
var filterUpdateOrigin = Builders<Patient>.Filter.And(filterUnit, originFilter);
|
||||
var updateOrigin = Builders<Patient>.Update
|
||||
.Set("origin.name", opt.UpdatedOption?.Name);
|
||||
await Collection.UpdateManyAsync(filterUpdateOrigin, updateOrigin);
|
||||
|
||||
await Collection.UpdateManyAsync(Builders<Patient>.Filter.And(filterUnit,
|
||||
Builders<Patient>.Filter.Eq(
|
||||
"originAux", opt.OldOption?.Name
|
||||
)), Builders<Patient>.Update
|
||||
.Set("originAux", opt.UpdatedOption?.Name));
|
||||
|
||||
// Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux)
|
||||
var originFilterToReturn = Builders<Patient>.Filter.Eq("origin.name", opt.UpdatedOption?.Name);
|
||||
var originAuxFilterToReturn = Builders<Patient>.Filter.Eq("originAux", opt.UpdatedOption?.Name);
|
||||
var originfilterToReturn = Builders<Patient>.Filter.And(
|
||||
filterUnit,
|
||||
Builders<Patient>.Filter.Or(originFilterToReturn, originAuxFilterToReturn)
|
||||
);
|
||||
|
||||
// Devolver los documentos actualizados
|
||||
var updatedDocumentsorigin = await Collection.Find(originfilterToReturn).ToListAsync();
|
||||
return updatedDocumentsorigin;
|
||||
|
||||
case MasterListType.DoctorTypeList:
|
||||
case MasterListType.AllergyList:
|
||||
case MasterListType.DestinationList:
|
||||
case MasterListType.ProcedureList:
|
||||
case MasterListType.ServiceList:
|
||||
case MasterListType.TreatmentList:
|
||||
case MasterListType.AltableOptionList:
|
||||
case MasterListType.DischargeStatusList:
|
||||
case MasterListType.InternalDestinationList:
|
||||
case MasterListType.LanguageBarrierList:
|
||||
case MasterListType.MobilityOptionList:
|
||||
case MasterListType.PassiveSittingList:
|
||||
case MasterListType.PatientStatusList:
|
||||
case MasterListType.TherapeuticCeilingList:
|
||||
case MasterListType.VisitOptionList:
|
||||
case MasterListType.AccessControlList:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> GetPatientsByUnitIds(List<ObjectId> unitIds, string typeName)
|
||||
{
|
||||
var isParsed = Enum.TryParse<MasterListType>(typeName, out _);
|
||||
if (!isParsed) return [];
|
||||
|
||||
var filterUnit = Builders<Patient>.Filter.In("unitId", unitIds);
|
||||
return await Collection.Find(filterUnit).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<long> CountByUnitId(ObjectId unitId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq(p => p.UnitId, unitId);
|
||||
return await Collection.CountDocumentsAsync(filter);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Logger.Error(e.Message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<Patient>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt,
|
||||
string typeName)
|
||||
{
|
||||
var isParsed = Enum.TryParse<MasterListType>(typeName, out var parsedTypeName);
|
||||
if (isParsed)
|
||||
{
|
||||
// Tener en cuenta los datos auxiliares ya que pueden ser texto libre o asignarse el establecido en la lista
|
||||
// originAux / diagnosisAux modificar en caso de ser el mismo que el padre
|
||||
// Notificar a todos los fronts con el nuevo valor de cada paciente por el id de los poc's afectados(?)
|
||||
var filterUnit = Builders<Patient>.Filter.In("unitId", unitIds);
|
||||
switch (parsedTypeName)
|
||||
{
|
||||
case MasterListType.DiagnosisList:
|
||||
|
||||
// Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux)
|
||||
var diagnosisFilterToReturn = Builders<Patient>.Filter.Eq("diagnosis.name", opt.Name);
|
||||
var diagnosisAuxFilterToReturn = Builders<Patient>.Filter.Eq("diagnosisAux", opt.Name);
|
||||
var filterToReturn = Builders<Patient>.Filter.And(
|
||||
filterUnit,
|
||||
Builders<Patient>.Filter.Or(diagnosisFilterToReturn, diagnosisAuxFilterToReturn)
|
||||
);
|
||||
|
||||
// Devolver los documentos actualizados
|
||||
var updatedDocuments = await Collection.Find(filterToReturn).ToListAsync();
|
||||
|
||||
var diagnosisFilter = Builders<Patient>.Filter.Eq(
|
||||
"diagnosis.name", opt.Name
|
||||
);
|
||||
var filterUpdateDiagnosis = Builders<Patient>.Filter.And(filterUnit, diagnosisFilter);
|
||||
var updateDiagnosis = Builders<Patient>.Update
|
||||
.Set(x => x.Diagnosis, null);
|
||||
await Collection.UpdateManyAsync(filterUpdateDiagnosis, updateDiagnosis);
|
||||
|
||||
await Collection.UpdateManyAsync(Builders<Patient>.Filter.And(filterUnit,
|
||||
Builders<Patient>.Filter.Eq(
|
||||
"diagnosisAux", opt.Name
|
||||
)), Builders<Patient>.Update
|
||||
.Set(x => x.DiagnosisAux, null));
|
||||
|
||||
|
||||
return updatedDocuments;
|
||||
case MasterListType.DoctorList:
|
||||
// Devolvemos los datos
|
||||
var doctorFilterToReturn = Builders<Patient>.Filter.ElemMatch(
|
||||
"doctors",
|
||||
Builders<Patient>.Filter.Eq("_id", opt.Id)
|
||||
);
|
||||
var filterToReturnDoctor = Builders<Patient>.Filter.And(filterUnit, doctorFilterToReturn);
|
||||
var updatedDoctorDocuments = await Collection.Find(filterToReturnDoctor).ToListAsync();
|
||||
|
||||
// Filtro para encontrar el elemento en el array `doctors` que coincida con el nombre
|
||||
var doctorFilter = Builders<Patient>.Filter.ElemMatch(
|
||||
"doctors",
|
||||
Builders<Patient>.Filter.Eq("_id", opt.Id)
|
||||
);
|
||||
var filterUpdateDoctor = Builders<Patient>.Filter.And(filterUnit, doctorFilter);
|
||||
|
||||
// Actualización del campo `name` en el array `doctors`
|
||||
var updateDoctor = Builders<Patient>.Update.PullFilter(
|
||||
"doctors", Builders<BsonDocument>.Filter.And(
|
||||
Builders<BsonDocument>.Filter.Eq("_id", opt.Id)
|
||||
));
|
||||
|
||||
// Ejecutar la actualización
|
||||
await Collection.UpdateManyAsync(filterUpdateDoctor, updateDoctor);
|
||||
|
||||
return updatedDoctorDocuments;
|
||||
case MasterListType.InsulationList:
|
||||
break;
|
||||
case MasterListType.OriginList:
|
||||
// Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux)
|
||||
var originFilterToReturn = Builders<Patient>.Filter.Eq("origin.name", opt.Name);
|
||||
var originAuxFilterToReturn = Builders<Patient>.Filter.Eq("originAux", opt.Name);
|
||||
var filterOriginToReturn = Builders<Patient>.Filter.And(
|
||||
filterUnit,
|
||||
Builders<Patient>.Filter.Or(originFilterToReturn, originAuxFilterToReturn)
|
||||
);
|
||||
|
||||
// Devolver los documentos actualizados
|
||||
var updatedDocumentsOrigin = await Collection.Find(filterOriginToReturn).ToListAsync();
|
||||
|
||||
var originFilter = Builders<Patient>.Filter.Eq(
|
||||
"origin.name", opt.Name
|
||||
);
|
||||
var filterUpdateOrigin = Builders<Patient>.Filter.And(filterUnit, originFilter);
|
||||
var updateOrigin = Builders<Patient>.Update
|
||||
.Set(x => x.Diagnosis, null);
|
||||
await Collection.UpdateManyAsync(filterUpdateOrigin, updateOrigin);
|
||||
|
||||
await Collection.UpdateManyAsync(Builders<Patient>.Filter.And(filterUnit,
|
||||
Builders<Patient>.Filter.Eq(
|
||||
"originAux", opt.Name
|
||||
)), Builders<Patient>.Update
|
||||
.Set(x => x.OriginAux, null));
|
||||
|
||||
|
||||
return updatedDocumentsOrigin;
|
||||
|
||||
case MasterListType.DoctorTypeList:
|
||||
case MasterListType.AllergyList:
|
||||
case MasterListType.DestinationList:
|
||||
case MasterListType.ProcedureList:
|
||||
case MasterListType.ServiceList:
|
||||
case MasterListType.TreatmentList:
|
||||
case MasterListType.AltableOptionList:
|
||||
case MasterListType.DischargeStatusList:
|
||||
case MasterListType.InternalDestinationList:
|
||||
case MasterListType.LanguageBarrierList:
|
||||
case MasterListType.MobilityOptionList:
|
||||
case MasterListType.PassiveSittingList:
|
||||
case MasterListType.PatientStatusList:
|
||||
case MasterListType.TherapeuticCeilingList:
|
||||
case MasterListType.VisitOptionList:
|
||||
case MasterListType.AccessControlList:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new List<Patient>();
|
||||
}
|
||||
|
||||
public async Task<Patient?> FindByPatientId(string patientId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(patientId)) return null;
|
||||
|
||||
//Último paciente admitido
|
||||
var patient = await Collection.Find(p => !p.DisTime.HasValue && patientId == p.PatientId)
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.AdmTime)).Limit(1).FirstOrDefaultAsync();
|
||||
|
||||
//Último con fecha de alta más reciente
|
||||
patient ??= await Collection.Find(p => p.DisTime.HasValue && patientId == p.PatientId)
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.DisTime)).Limit(1).FirstOrDefaultAsync();
|
||||
|
||||
return patient;
|
||||
}
|
||||
|
||||
public async Task<Patient?> FindByPatientId(ObjectId patientId)
|
||||
{
|
||||
//Último paciente admitido
|
||||
var patient = await Collection.Find(p => !p.DisTime.HasValue && patientId == p.Id)
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.AdmTime)).Limit(1).FirstOrDefaultAsync();
|
||||
|
||||
//Último con fecha de alta más reciente
|
||||
patient ??= await Collection.Find(p => p.DisTime.HasValue && patientId == p.Id)
|
||||
.Sort(Builders<Patient>.Sort.Descending(p => p.DisTime)).Limit(1).FirstOrDefaultAsync();
|
||||
|
||||
return patient;
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindAll()
|
||||
{
|
||||
return (await Collection.FindAsync(Builders<Patient>.Filter.Empty)).ToList();
|
||||
//return (await Collection.FindAsync(_ => true)).ToList();
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindByPointOfCare(string pointOfCare)
|
||||
{
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var filter = filterBuilder.Eq(pa => pa.UnitString, pointOfCare);
|
||||
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindByPointOfCare(ObjectId pointOfCare)
|
||||
{
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var filter = filterBuilder.Eq(pa => pa.PointOfCareId, pointOfCare);
|
||||
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindInActivePoC()
|
||||
{
|
||||
var virtualPointOfCareValues = Enum.GetValues(typeof(VirtualPointOfCare)).Cast<VirtualPointOfCare>()
|
||||
.Select(p => p.ToString())
|
||||
.ToList();
|
||||
|
||||
//var filterBuilder = Builders<Patient>.Filter;
|
||||
|
||||
// Define el pipeline de agregación
|
||||
var pipeline = new[]
|
||||
{
|
||||
new BsonDocument("$lookup", new BsonDocument
|
||||
{
|
||||
{ "from", "pointOfCares" }, // Colección de PointOfCare
|
||||
{ "localField", "pointOfCareId" },
|
||||
{ "foreignField", "_id" },
|
||||
{ "as", "pointOfCareInfo" }
|
||||
}),
|
||||
new BsonDocument("$unwind", "$pointOfCareInfo"),
|
||||
new BsonDocument("$match", new BsonDocument
|
||||
{
|
||||
{ "pointOfCareInfo.bed", new BsonDocument("$nin", new BsonArray(virtualPointOfCareValues)) }
|
||||
})
|
||||
};
|
||||
|
||||
var result = await Collection.Aggregate<Patient>(pipeline).ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<Patient>> FindInInactivePoC()
|
||||
{
|
||||
var virtualPointOfCareValues = Enum.GetValues(typeof(VirtualPointOfCare)).Cast<VirtualPointOfCare>()
|
||||
.Select(p => p.ToString())
|
||||
.ToList();
|
||||
|
||||
//var filterBuilder = Builders<Patient>.Filter;
|
||||
|
||||
// Define el pipeline de agregación
|
||||
var pipeline = new[]
|
||||
{
|
||||
new BsonDocument("$lookup", new BsonDocument
|
||||
{
|
||||
{ "from", "pointOfCares" }, // Colección de PointOfCare
|
||||
{ "localField", "pointOfCareId" },
|
||||
{ "foreignField", "_id" },
|
||||
{ "as", "pointOfCareInfo" }
|
||||
}),
|
||||
new BsonDocument("$unwind", "$pointOfCareInfo"),
|
||||
new BsonDocument("$match", new BsonDocument
|
||||
{
|
||||
{ "pointOfCareInfo.bed", new BsonDocument("$in", new BsonArray(virtualPointOfCareValues)) }
|
||||
})
|
||||
};
|
||||
|
||||
var result = await Collection.Aggregate<Patient>(pipeline).ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
public IFindFluent<Patient, Patient> GetPaginatedPatients(PaginationFilter filter)
|
||||
{
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var sort = Builders<Patient>.Sort.Descending("admTime");
|
||||
var filters = new List<FilterDefinition<Patient>>();
|
||||
|
||||
if (filter.FilteredRequest != null)
|
||||
{
|
||||
AddDefaultFilters(filters, filter, filterBuilder);
|
||||
// return CreateFindFluent(filters, sort);
|
||||
}
|
||||
|
||||
var requestFilter = filter.FilteredRequest;
|
||||
|
||||
if(requestFilter == null) return CreateFindFluent(filters, sort);
|
||||
|
||||
AddTimeFilters(requestFilter, filters, filterBuilder);
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.FilteredRequest?.Text))
|
||||
{
|
||||
var textFilter = filter.FilteredRequest.Text;
|
||||
var textFilterEscaped = Regex.Escape(textFilter);
|
||||
|
||||
var orFilters = new List<FilterDefinition<Patient>>
|
||||
{
|
||||
filterBuilder.Regex(p => p.Person!.FirstName, new BsonRegularExpression(textFilterEscaped, "i")),
|
||||
filterBuilder.Regex(p => p.Person!.SecondName, new BsonRegularExpression(textFilterEscaped, "i")),
|
||||
filterBuilder.Regex(p => p.Person!.LastName, new BsonRegularExpression(textFilterEscaped, "i")),
|
||||
filterBuilder.Regex(p => p.PatientNumber, new BsonRegularExpression(textFilterEscaped, "i"))
|
||||
};
|
||||
|
||||
if (ObjectId.TryParse(textFilter, out var id)) orFilters.Add(filterBuilder.Eq("_id", id));
|
||||
|
||||
filters.Add(filterBuilder.Or(orFilters));
|
||||
}
|
||||
|
||||
if (filter.FilteredRequest?.UnitId != null && ObjectId.TryParse(filter.FilteredRequest.UnitId, out var unitId))
|
||||
filters.Add(filterBuilder.Eq("unitId", unitId));
|
||||
if (filter.FilteredRequest?.PocId != null && ObjectId.TryParse(filter.FilteredRequest.PocId, out var pocId))
|
||||
filters.Add(filterBuilder.Eq("pointOfCareId", pocId));
|
||||
return CreateFindFluent(filters, sort);
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<Patient>> FindPatientsNotUpdatedSince(DateTime date)
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Or(
|
||||
Builders<Patient>.Filter.Lt(p => p.UpdateDate, date),
|
||||
Builders<Patient>.Filter.Eq(p => p.UpdateDate, null)
|
||||
);
|
||||
return await Collection.Find(filter).ToListAsync();
|
||||
|
||||
//return await Collection.Find(p => p.UpdateDate < date).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<Patient>> FindDischargedPatients()
|
||||
{
|
||||
try
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Ne(p => p.DisTime, null);
|
||||
var cursor = await Collection.FindAsync(filter);
|
||||
var patients = await cursor.ToListAsync();
|
||||
|
||||
return patients;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Error finding discharged patients {exMessage}", ex.Message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Patient?> UpdateOne(Patient updatedPatient)
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq("_id", updatedPatient.Id);
|
||||
|
||||
var update = Builders<Patient>.Update
|
||||
.Set(p => p.PatientNumber, updatedPatient.PatientNumber)
|
||||
.Set(p => p.Person, updatedPatient.Person)
|
||||
.Set(p => p.UpdateDate, DateTime.UtcNow);
|
||||
|
||||
return await Collection.FindOneAndUpdateAsync(filter, update,
|
||||
new FindOneAndUpdateOptions<Patient, Patient> { ReturnDocument = ReturnDocument.After });
|
||||
}
|
||||
|
||||
public async Task<Patient?> UpdatePatientIncomingData(ObjectId patientId, Patient person)
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq("_id", patientId);
|
||||
var update = Builders<Patient>.Update
|
||||
.Set(p => p.OriginAux, person.OriginAux)
|
||||
.Set(p => p.DiagnosisAux, person.DiagnosisAux)
|
||||
.Set(p => p.Diagnosis, person.Diagnosis)
|
||||
.Set(p => p.UpdateDate, DateTime.UtcNow)
|
||||
.Set(p => p.AdmTime, person.AdmTime)
|
||||
.Set(p => p.Origin, person.Origin);
|
||||
|
||||
return await Collection.FindOneAndUpdateAsync(filter, update,
|
||||
new FindOneAndUpdateOptions<Patient, Patient> { ReturnDocument = ReturnDocument.After });
|
||||
}
|
||||
|
||||
public async Task<Patient?> UpdatePatientDemographicData(ObjectId patientId, Patient person)
|
||||
{
|
||||
var filter = Builders<Patient>.Filter.Eq("_id", patientId);
|
||||
var update = Builders<Patient>.Update
|
||||
.Set(p => p.UpdateDate, DateTime.UtcNow)
|
||||
.Set(p => p.Allergies, person.Allergies)
|
||||
.Set(p => p.LanguageBarrier, person.LanguageBarrier)
|
||||
.Set(p => p.DiagnosisAux, person.DiagnosisAux)
|
||||
.Set(p => p.Diagnosis, person.Diagnosis)
|
||||
.Set(p => p.Person, person.Person);
|
||||
|
||||
|
||||
return await Collection.FindOneAndUpdateAsync(filter, update,
|
||||
new FindOneAndUpdateOptions<Patient, Patient> { ReturnDocument = ReturnDocument.After });
|
||||
}
|
||||
|
||||
|
||||
public override async Task CreateIndexes()
|
||||
{
|
||||
var options = new CreateIndexOptions<Patient> { Background = true, Unique = false };
|
||||
var optionsUq = new CreateIndexOptions<Patient>
|
||||
{
|
||||
Background = true,
|
||||
Unique = true
|
||||
//PartialFilterExpression = Builders<Patient>.Filter.Exists(p => p.PointOfCareId) &
|
||||
// Builders<Patient>.Filter.Exists(p => p.UnitId)
|
||||
};
|
||||
var indexes = new List<CreateIndexModel<Patient>>
|
||||
{
|
||||
new("{ patientNumber: 1 }", optionsUq),
|
||||
new("{ admTime: 1 }", options)
|
||||
//new("{ pointOfCareId: 1, unitId: 1 }", optionsUq),
|
||||
//new("{ pointOfCareId: 1 }", optionsUq)
|
||||
};
|
||||
|
||||
await MongoUtils.EnsureIndexes(Collection, indexes);
|
||||
}
|
||||
|
||||
private static void AddTimeFilters(FilteredRequest requestFilter, List<FilterDefinition<Patient>> filters,
|
||||
FilterDefinitionBuilder<Patient> filterBuilder)
|
||||
{
|
||||
// Filter by admission time
|
||||
if (requestFilter.StartAdmTime.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.AdmTime, requestFilter.StartAdmTime.Value));
|
||||
if (requestFilter.EndAdmTime.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.AdmTime, requestFilter.EndAdmTime.Value));
|
||||
|
||||
// Filter by discharge time
|
||||
if (requestFilter.StartDischargeTime.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.DisTime, requestFilter.StartDischargeTime.Value));
|
||||
if (requestFilter.EndDischargeTime.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.DisTime, requestFilter.EndDischargeTime.Value));
|
||||
|
||||
// Filter by last observation time
|
||||
if (requestFilter.StartLastObsTime.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.LastObservationDate, requestFilter.StartLastObsTime.Value));
|
||||
if (requestFilter.EndLastObsTime.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.LastObservationDate, requestFilter.EndLastObsTime.Value));
|
||||
|
||||
// Filter by creation date
|
||||
if (requestFilter.StartCreationDateTime.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.CreationDate, requestFilter.StartCreationDateTime.Value));
|
||||
if (requestFilter.EndCreationDateTime.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.CreationDate, requestFilter.EndCreationDateTime.Value));
|
||||
|
||||
// Filter by update date
|
||||
if (requestFilter.StartUpDateTime.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.UpdateDate, requestFilter.StartUpDateTime.Value));
|
||||
if (requestFilter.EndUpDateTime.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.UpdateDate, requestFilter.EndUpDateTime.Value));
|
||||
|
||||
// Filter by birth date (with Person null check)
|
||||
if (requestFilter.StartBirthDate.HasValue || requestFilter.EndBirthDate.HasValue)
|
||||
{
|
||||
// Check if Person is not null
|
||||
filters.Add(filterBuilder.Exists(p => p.Person));
|
||||
|
||||
// Apply birth date filters only if Person is not null
|
||||
if (requestFilter.StartBirthDate.HasValue)
|
||||
filters.Add(filterBuilder.Gte(p => p.Person!.BirthDate, requestFilter.StartBirthDate.Value));
|
||||
if (requestFilter.EndBirthDate.HasValue)
|
||||
filters.Add(filterBuilder.Lte(p => p.Person!.BirthDate, requestFilter.EndBirthDate.Value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<Patient>> FindAllByPointOfCareId(ObjectId pointOfCare)
|
||||
{
|
||||
var filterBuilder = Builders<Patient>.Filter;
|
||||
var filter = filterBuilder.Eq(pa => pa.PointOfCareId, pointOfCare);
|
||||
|
||||
var result = await Collection.FindAsync(filter);
|
||||
|
||||
return await result.ToListAsync();
|
||||
}
|
||||
|
||||
private void AddDefaultFilters(List<FilterDefinition<Patient>> filters, PaginationFilter filter,
|
||||
FilterDefinitionBuilder<Patient> filterBuilder)
|
||||
{
|
||||
// Verifica si PatientId tiene valor
|
||||
if (filter.FilteredRequest?.PatientId != null)
|
||||
{
|
||||
if(ObjectId.TryParse(filter.FilteredRequest.PatientId, out var patientId))
|
||||
filters.Add(
|
||||
filterBuilder.Eq(p => p.Id, patientId)
|
||||
);
|
||||
}
|
||||
|
||||
// Verifica si PatientNumber tiene valor
|
||||
else if (filter.FilteredRequest?.PatientNumber != null)
|
||||
filters.Add(
|
||||
filterBuilder.Eq(p => p.PatientNumber, filter.FilteredRequest.PatientNumber)
|
||||
);
|
||||
}
|
||||
|
||||
private IFindFluent<Patient, Patient> CreateFindFluent(List<FilterDefinition<Patient>> filters,
|
||||
SortDefinition<Patient> sort)
|
||||
{
|
||||
var combinedFilter = filters.Any()
|
||||
? Builders<Patient>.Filter.And(filters)
|
||||
: Builders<Patient>.Filter.Empty;
|
||||
|
||||
return Collection.Find(combinedFilter).Sort(sort);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user