Ramda find function in array of nested objects - node.js

I am trying to use find function in this array
array= [{
type: 'banks',
id: 25,
attributes: { name: 'Bradescard', bankNumber: '063' },
links: { self: '/banks/63' }
},
{
type: 'banks',
id: 26,
attributes: { name: 'BM Goldman Sachs', bankNumber: '064' },
links: { self: '/banks/64' }
},
{
type: 'banks',
id: 27,
attributes: { name: 'Bracce', bankNumber: '065' },
links: { self: '/banks/65' }
}
]
if I try find(propEq('id', 27))(array) it returns the correct object, but I need to find by bankNumber.
I tried find(propEq(lensPath(['attributes', 'bankNumber']), '065'))(array) but I got undefined
How can I do this?

Try to just switch propEq to pathEq.
Something like: find(pathEq(['attributes', 'bankNumber'], '065'))(array).

Related

How to Remove Specific Text / String Out of Array Object Values

I am using Node.js 16.17 and Express.
Forgive me if this is answered elsewhere, if a solution exists elsewhere, please point me in that direction.
On my server side, I have an array with objects with properties and their values. I want to be able to remove specific text/string from the property values.
What I Have
I currently have an array with objects (and sometimes arrays and object nested within):
DataArray =
[
{
page: {
results: [
{
id: '1234',
title: 'TextIWantA **(Text) I Dont Want**',
children: {
page: {
results: [
{
id: '5678',
title: 'ChildA TextIWant **(Text I) Dont Want**',
},
{
id: '9101',
title: 'ChildB TextIWant **(Text I) Dont Want**',
children: {
page: {
results: [
{
id: 'abcd',
title: 'GrandchildA TextIWant **(Text I (Dont) Want**',
}
]
}
}
},
],
},
},
},
{
id: '1121',
title: 'TextIWantB **(Text) I Dont Want**',
}
]
}
}
]
I am able to flatten this structure with this function:
function flatten(arr) {
const flattened = []
for (const { children, ...element } of arr) {
flattened.push(element)
if (children) {
flattened.push(...flatten(children.page.results))
}
}
return flattened;
}
const flat = [{ page: { results: flatten(DataArray[0].page.results) } }]
console.log(flat[0].page.results)
The returned data is:
[
{ id: '1234', 'page', title: 'TextIWantA **(Text) I Dont Want**' },
{ id: '5678', 'page', title: 'ChildA TextIWant **(Text I) Dont Want**' },
{ id: '9101', 'page', title: 'ChildB TextIWant **(Text I) Dont Want**' },
{ id: 'abcd', 'page', title: 'GrandchildA TextIWant **(Text I (Dont) Want**' },
{ id: '1121', 'page', title: 'TextIWantB **(Text) I Dont Want**' }
]
I am making an assumption that I have to change my text to a string in order to replace it then parse it again to turn back into an object. I'm happy to learn my assumption is true or incorrect, if incorrect, how to fix to be able to remove text.
So if I try to do a replace using the following, 1) it does not work and 2) it does not differentiate for the different text to remove (perhaps I just run multiple/different replaces/filters?):
const veryFlat = flat;
var veryFlatData = veryFlat.map(function(x){return x.toString().replace(/ **(Text) I Dont Want**/g, '');});
var removedTextData= JSON.parse(veryFlatData);
console.log(removedTextData);
Desired Result
I want to be able to remove all of the variances of Text I Dont Want, so the end result would look like (of now it will be flattened as seen above)
DataArray =
[
{
page: {
results: [
{
id: '1234',
title: 'TextIWantA',
children: {
page: {
results: [
{
id: '5678',
title: 'ChildA TextIWant',
},
{
id: '9101',
title: 'ChildB TextIWant',
children: {
page: {
results: [
{
id: 'abcd',
title: 'GrandchildA TextIWant',
}
]
}
}
},
],
},
},
},
{
id: '1121',
title: 'TextIWantB',
}
]
}
}
]
Each title is unique and I don't seem able to find anything to even say I've tried this or that.
I don't want to use .startswith or .length or .index and would prefer to avoid regex, and the example above using .replace doesn't seem to work.
How do I reach into these property values and rip out the text I don't want?
Thank you for any help you can provide.

How to grab field value during a MongooseModel.bulkWrite operation?

Context:
I am trying to upsert in bulk an array of data, with an additional computed field: 'status'.
Status should be either :
- 'New' for newly inserted docs;
- 'Removed' for docs present in DB, but inexistent in incoming dataset;
- a percentage explaining the evolution for the field price, comparing the value in DB to the one in incoming dataset.
Implementations:
data.model.ts
import { Document, model, Model, models, Schema } from 'mongoose';
import { IPertinentData } from './site.model';
const dataSchema: Schema = new Schema({
sourceId: { type: String, required: true },
name: { type: String, required: true },
price: { type: Number, required: true },
reference: { type: String, required: true },
lastModified: { type: Date, required: true },
status: { type: Schema.Types.Mixed, required: true }
});
export interface IData extends IPertinentData, Document {}
export const Data: Model<IData> = models.Data || model<IData>('Data', dataSchema);
data.service.ts
import { Data, IPertinentData } from '../models';
export class DataService {
static async test() {
// await Data.deleteMany({});
const data = [
{
sourceId: 'Y',
reference: `y0`,
name: 'y0',
price: 30
},
{
sourceId: 'Y',
reference: 'y1',
name: 'y1',
price: 30
}
];
return Data.bulkWrite(
data.map(function(d) {
let status = '';
// #ts-ignore
console.log('price', this);
// #ts-ignore
if (!this.price) status = 'New';
// #ts-ignore
else if (this.price !== d.price) {
// #ts-ignore
status = (d.price - this.price) / this.price;
}
return {
updateOne: {
filter: { sourceId: d.sourceId, reference: d.reference },
update: {
$set: {
// Set percentage value when current price is greater/lower than new price
// Set status to nothing when new and current prices match
status,
name: d.name,
price: d.price
},
$currentDate: {
lastModified: true
}
},
upsert: true
}
};
}
)
);
}
}
... then in my backend controller, i just call it with some route :
try {
const results = await DataService.test();
return new HttpResponseOK(results);
} catch (error) {
return new HttpResponseInternalServerError(error);
}
Problem:
I've tried lot of implementation syntaxes, but all failed either because of type casting, and unsupported syntax like the $ symbol, and restrictions due to the aggregation...
I feel like the above solution might be closest to a working scenario but i'm missing a way to grab the value of the price field BEFORE the actual computation of status and the replacement with updated value.
Here the value of this is undefined while it is supposed to point to current document.
Questions:
Am i using correct Mongoose way for a bulk update ?
if yes, how to get the field value ?
Environment:
NodeJS 13.x
Mongoose 5.8.1
MongoDB 4.2.1
EUREKA !
Finally found a working syntax, pfeeeew...
...
return Data.bulkWrite(
data.map(d => ({
updateOne: {
filter: { sourceId: d.sourceId, reference: d.reference },
update: [
{
$set: {
lastModified: Date.now(),
name: d.name,
status: {
$switch: {
branches: [
// Set status to 'New' for newly inserted docs
{
case: { $eq: [{ $type: '$price' }, 'missing'] },
then: 'New'
},
// Set percentage value when current price is greater/lower than new price
{
case: { $ne: ['$price', d.price] },
then: {
$divide: [{ $subtract: [d.price, '$price'] }, '$price']
}
}
],
// Set status to nothing when new and current prices match
default: ''
}
}
}
},
{
$set: { price: d.price }
}
],
upsert: true
}
}))
);
...
Explanations:
Several problems were blocking me :
the '$field_value_to_check' instead of this.field with undefined 'this' ...
the syntax with $ symbol seems to work only within an aggregation update, using update: [] even if there is only one single $set inside ...
the first condition used for the inserted docs in the upsert process needs to check for the existence of the field price. Only the syntax with BSON $type worked...
Hope it helps other devs in same scenario.

values must be an object with value names as keys

I have created an enum type for my object
const MonthType = new GraphQLEnumType({
name: 'monthType',
value: {
JANUARY:{
value: "January"
},
FEBRUARY: {
value: 'February'
},
MARCH: {
value: 'March'
},
MAY: {
value: 'May'
},
JUNE: {
value: 'June'
},
JULY: {
value: 'July'
},
AUGUST: {
value: "August"
},
SEPTEMBER: {
value: 'September'
},
OCTOBER: {
value: 'October'
},
NOVEMEBER: {
value: 'November'
},
DECEMBER: {
value: 'December'
}
}
})
which I am using kind of like this in my Object type
const UserType = new GraphQLObjectType({
name: 'User', // Importance of Name here
fields: () => ({
id: {
type: GraphQLInt
},
userId: {
type: GraphQLInt
},
gradMonth: {
type: MonthType
},
Now, Whenever I start my express server, I am thrown the following error in my code
monthType values must be an object with value names as keys
What I intend to do? I want the user to select, pass the value of the month which should be one of these.
Can someone help me in figuring out why I am getting the following error?
Try replacing value by values at the begining :
const MonthType = new GraphQLEnumType({
name: 'monthType',
values: { // <=== here
//...

Why isn't Elasticsearch detecting my custom made analyzer?

I made an index "user-name" with a custom made analyzer called 'autocomplete':
client.indices.create({
index: 'user-name',
type: 'text',
settings: {
analysis: {
filter: {
autocomplete_filter: {
type: 'edge-ngram',
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: 'custom',
tokenizer: 'standard',
filter: [
'lowercase',
'autocomplete_filter'
]
}
}
}
}
}
Then I try to reference this custom made analyzer by trying to use it in a mapping:
client.indices.putMapping({
index: 'user-name',
type: 'text',
body: {
properties: {
name: {
type: 'string',
analyzer: 'autocomplete',
search_analyzer: 'standard'
}
}
}
})
but then I get this error: "reason": "analyzer [autocomplete] not found for field [name]". Why isn't my autocomplete analyzer being detected? Thanks.
You're almost there. You simply need to put the index settings inside the body parameter:
client.indices.create({
index: 'user-name',
type: 'text',
body: {
settings: {
analysis: {
filter: {
autocomplete_filter: {
type: 'edge-ngram',
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: 'custom',
tokenizer: 'standard',
filter: [
'lowercase',
'autocomplete_filter'
]
}
}
}
}
}
}

I want to remove my array list

my array list is below:
this.array_of_name = ko.observableArray([
{ name: 'All Ways' },
{ name: 'Brand Cars' },
{ name: 'Carrom' },
{ name: 'Ginger' },
{ name: 'Honey' },
{ name: 'Jar Jar' },
{ name: 'Bert' },
{ name: 'Kitjar' },
{ name: 'Denise' },
{ name: 'Numeric' },
{ name: 'Length' },
{ name: 'Orange' },
{ name: 'Panasonic' },
{ name: 'Rabbit' },
{ name: 'Tarzan' },
{ name: 'USA' },
{ name: 'Yield' },
{ name: 'Zen' }
]);
i want to remove all items from it using javascript or knockout.
And also want to add search functionality using javascript or knockout.
var newArray = [];
var a=["a","b","c"];
for(var i=0;i<a.length;i++)
if(a[i]!=="a") newArray.push(a[i]);
Or another approach
removeAll = function(ary, elem) {
return ary.filter(function(e) { return e != elem });
}
to make empty, just assign empty array to your variable.
ex: this.array_of_name = ko.observableArray([]);

Resources