Попробуй. Я переделал реализацию, это произошло более универсально. Анализирует любые фильтры в соответствии с вашим алгоритмом, который он находит. Все тестовые случаи работают.
Ссылка песочницы: https://codesandbox.io/s/optimistic-mirzakhani-pogpw-so-i1u6h
let filterObj = {
feature: "test",
filter: {
and: [
{
field: "field1",
value: "2"
}
]
}
};
let obj = [
{
field: "field1",
value: "2"
},
{
field: "field1",
value: "1"
}
];
var FilterController = function(filter) {
var self = this;
self.filter = filter;
// encapsulated map of objects by fields
var storeMap = {};
// counter of objects
var counter = 0;
var tryPutObjectToMap = function(object) {
if (typeof object === "object") {
// get type for grouping
var objectType = self.getObjectGroupType(object);
if (objectType !== null) {
// cheack have group
if (!storeMap.hasOwnProperty(objectType)) {
storeMap[objectType] = [];
}
var duplicate = storeMap[objectType].find(function(sObject) {
return self.getObjectValue(sObject) === self.getObjectValue(object);
});
// check duplicate
if (duplicate === undefined) {
counter++;
storeMap[objectType].push(object);
} else {
// TODO: Handle duplicates
}
} else {
// TODO: handle incorrect object
}
}
};
// get filter structure from map
var getFilterStructureFromMap = function() {
var result = {};
// check exists root filter and filed if have objects
if (counter > 0) {
result["and"] = [];
}
for (var key in storeMap) {
if (storeMap.hasOwnProperty(key)) {
var array = storeMap[key];
if (array.length > 1) {
result["and"].push({
// clone array
or: array.slice()
});
} else {
result["and"].push(array[0]);
}
}
}
return result;
};
// rewrite and get current filter
// if you need^ create new object for result
self.rewriteAndGetFilter = function() {
self.filter.filter = getFilterStructureFromMap();
return self.filter;
};
// not prototype function for have access to storeMap
self.putObjects = function(objects) {
if (Array.isArray(objects)) {
// recursive push array elements
objects.forEach(element => self.putObjects(element));
// handle array
} else if (typeof objects === "object") {
// handle object
if (objects.hasOwnProperty("and") || objects.hasOwnProperty("or")) {
for (var key in objects) {
//no matter `or` or `and` the same grouping by field
// inner object field
if (objects.hasOwnProperty(key)) {
self.putObjects(objects[key]);
}
}
} else {
// filters props not found, try push to store map
tryPutObjectToMap(objects);
}
} else {
// TODO: Handle errors
}
};
if (self.filter.hasOwnProperty("filter")) {
// put and parse current objects from filter
self.putObjects(self.filter.filter);
}
};
// function for grouping objects.
// for you get filed name from object.
// change if need other ways to compare objects.
FilterController.prototype.getObjectGroupType = function(obj) {
if (typeof obj === "object" && obj.hasOwnProperty("field")) {
return obj.field;
}
return null;
};
// get object value
FilterController.prototype.getObjectValue = function(obj) {
if (typeof obj === "object" && obj.hasOwnProperty("value")) {
return obj.value;
}
return null;
};
var ctrl = new FilterController(filterObj);
ctrl.putObjects(obj);
var totalFilter = ctrl.rewriteAndGetFilter();
console.log(totalFilter);
console.log(JSON.stringify(totalFilter));
РЕДАКТИРОВАТЬ 1
Я не сделал изменить логику; Я сделал на его основе функцию.
let filterObj = {
feature: "test",
filter: {
and: [
{
field: "field1",
value: "2"
}
]
}
};
let obj = [
{
field: "field1",
value: 2
},
{
field: "field1",
value: "1"
}
];
function appendToFilter(filter, inputObjects) {
var storeMap = {};
var counter = 0;
var handlingQueue = [];
// if filter isset the appen to handling queue
if (filter.hasOwnProperty("filter")) {
handlingQueue.push(filter.filter);
}
// append other object to queue
handlingQueue.push(inputObjects);
// get first and remove from queue
var currentObject = handlingQueue.shift();
while (currentObject !== undefined) {
if (Array.isArray(currentObject)) {
currentObject.forEach(element => handlingQueue.push(element));
} else if (typeof currentObject === "object") {
if (currentObject.hasOwnProperty("and") || currentObject.hasOwnProperty("or")) {
for (var key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
handlingQueue.push(currentObject[key]);
}
}
} else {
// TODO: append fild exists check
if (currentObject.field) {
if (!storeMap.hasOwnProperty(currentObject.field)) {
storeMap[currentObject.field] = [];
}
var localValue = currentObject.value;
// check duplicate
if (storeMap[currentObject.field].find(object => object.value === localValue) === undefined) {
counter++;
storeMap[currentObject.field].push(currentObject);
}
}
}
}
currentObject = handlingQueue.shift();
}
// create new filter settings
var newFilter = {};
// check exists root filter and filed if have objects
if (counter > 0) { newFilter["and"] = []; }
for (var storeKey in storeMap) {
if (storeMap.hasOwnProperty(storeKey)) {
var array = storeMap[storeKey];
if (array.length > 1) {
newFilter["and"].push({
// clone array
or: array.slice()
});
} else {
newFilter["and"].push(array[0]);
}
}
}
filter.filter = newFilter;
}
// update filterObj
appendToFilter(filterObj, obj);
console.log(filterObj);
РЕДАКТИРОВАТЬ 2,3 (ОБНОВЛЕНО)
С поддержкой других объектов.
export function appendToFilter(filter, inputObjects) {
var storeMap = {};
var others = [];
var counter = 0;
var handlingQueue = [];
// if filter isset the appen to handling queue
if (filter.hasOwnProperty("filter") && filter.filter.hasOwnProperty("and")) {
handlingQueue.push(filter.filter.and);
}
// append other object to queue
handlingQueue.push(inputObjects);
// get first and remove from queue
var currentObject = handlingQueue.shift();
while (currentObject !== undefined) {
if (Array.isArray(currentObject)) {
currentObject.forEach(element => handlingQueue.push(element));
} else if (typeof currentObject === "object") {
if (
currentObject.hasOwnProperty("and") ||
currentObject.hasOwnProperty("or")
) {
for (var key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
handlingQueue.push(currentObject[key]);
}
}
} else {
// TODO: append fild exists check
if (currentObject.field) {
if (!storeMap.hasOwnProperty(currentObject.field)) {
storeMap[currentObject.field] = [];
}
var localValue = currentObject.value;
// check duplicate
if (
storeMap[currentObject.field].find(
object => object.value === localValue
) === undefined
) {
counter++;
storeMap[currentObject.field].push(currentObject);
}
} else {
// handle others objects^ without field "field"
counter++;
others.push(currentObject);
}
}
}
currentObject = handlingQueue.shift();
}
// create new filter settings
var newFilter = {};
// check exists root filter and filed if have objects
if (counter > 0) {
newFilter["and"] = [];
}
for (var storeKey in storeMap) {
if (storeMap.hasOwnProperty(storeKey)) {
var array = storeMap[storeKey];
if (array.length > 1) {
newFilter["and"].push({
// clone array
or: array.slice()
});
} else {
newFilter["and"].push(array[0]);
}
}
}
// Append others to result filter
others.forEach(other => newFilter["and"].push(other));
filter.filter = newFilter;
}