update elasticcache record without totally replacing it - ruby

I'm using this to add a bunch of records to the elasticcache index:
def self.index_trends(trend_hashes)
formatted_trends = trend_hashes.map do |trend_hash|
{
index: {
_index: 'trends',
_type: 'trend',
_id: trend_hash["id"],
data: trend_hash
}
}
end
elasticsearch.bulk({
body: formatted_trends
})
end
Now I need to update a record (given its id). I want to just add one key-val to the data hash, not replace the whole state. How can I do this using elasticsearch-ruby?

I dont know how to do this with ruby, but in ES there is update API.
Which look like this
POST test/type1/1/_update
{
"script" : "ctx._source.new_field = \"value_of_new_field\""
}
From example with ruby should be
client.update index: 'myindex', type: 'mytype', id: '1',
body: { script: 'ctx._source.tags += tag', params: { tag: 'x' } }

Related

How to GET a document from an index inside of an alias

I have inserted a few of my indexes inside of an alias because I've updated the index mapping a few times. I am looking to query my indexes behind my alias for potential documents depending on the search criteria.
I've been querying using just indexes up until now, like so -
const { body: clientBody } = await client.search({
index: 'my-index',
filter_path: 'hits.hits._source',
body: { query: { bool: esObject } },
size: 10000,
});
but as I now have multiple indexes I wish to query inside of my alias I have created (my-alias) this no longer works as needed. I've tried replacing the index for alias but this does not work. Is there something I'm missing?
How I've added my indexes to my alias.
await client.indices.updateAliases(
{[
{
add: {
index: 'my-index-1',
alias: 'my-alias',
},
},
{
add: {
index: 'my-index-2'
alias: 'my-alias'
},
},
]});
According to the nodejs package. The index will be used as the target, as we can see from here.
So the solution was to just change my index, and stop it pointing at 'my-index' but rather at 'my-alias' instead.
const { body: clientBody } = await client.search({
index: 'my-alias',
filter_path: 'hits.hits._source',
body: { query: { bool: esObject } },
size: 10000,
});

How to dynamically access the names of fields being queries in a GraphQL resolver?

I have two collections:
dbPosts
id: mongoose.Schema.Types.ObjectId,
title: { type: String },
content: { type: String },
excerpt: { type: String },
slug: { type: String },
author: {
id: { type: String },
fname: { type: String },
lname: { type: String },
}
dbAuthors
id: mongoose.Schema.Types.ObjectId,
fname: { type: String },
lname: { type: String },
posts: [
id: { type: String },
title: { type: String }
]
I resolve my author queries as follows:
Query: {
authors: (parent, root, args, context) => {
return dbAuthor.find({});
},
author: (root, args, context) => {
return dbAuthor.findById(args.id);
},
},
Author: {
posts: (parent) => {
if(parent.posts) {
return parent.posts;
} else {
return dbAuthor.find({'author.id': parent.id});
}
},
}
The reason I'm resolving thus is to optimize my MongoDB requests by denormalizing my relationships. Here's the objective:
If you need just a list of authors with the titles of their works, all necessary fields are right there in dbAuthors, so no need to look up dbPosts. But if you need more details on each post returned, say, excerpts or slug, you look up dbPosts for the following condition:
{'author.id': parent.id}
But the problem is, if your query looks like this:
authors(id: "3") {
fname
lname
posts {
title
excerpt
}
}
it breaks, because there's no excerpt field returned in the parent object. This problem could be easily fixed if there were some way I could determine what fields are being queried on an author's posts field and then decide if the values returned in parent would suffice. If not, I could then proceed to look up dbPosts with the author's id value. Is it possible? Because if not, it would defeat the whole purpose of denormalizing your collections, something Mongo strongly urges you to do!
It's rather denormalized - data is duplicated ;)
You're probably looking for info.fieldNodes

Sequelize include with multiple where condition

I have a bit of problem for using Sequelize with include. The problem is that my model uses two primary keys in child table.
So it goes like this
Parent table
User : Id, ...
Post : Id, UserId(foreign key, binds to user id), ...
Post Hash Tag : HashTag, PostId(foreign key, binds to Post id), UserId(foreign key, binds to user id of Post table)
So the table hierarchy looks like this
user - post - post hash tag
Now when I try to do like this,
Post.findAll(
include: {
model: post hash tag
}
)
then it only searches the post hash tags for where post id of post hash tag table is equal to post id of post table
So I added like this
Post.findAll(
include: {
model: post hash tag
where: {
col1: models.sequelize.where(models.sequelize.col('POST.USER_ID'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
}
}
);
Then it will gives a problem at 'where' clause that Post.USER_ID cannot be found.
If I change col1 value to Post.userId then now it solves the above error but gives another error at 'on' clause
Do you have any idea how I can solve this?
The full model is given here
User
sequelize.define('User', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey : true }
)
Post - I know multiple primary declaration is not working correctly, so don't bother to consider too much
sequelize.define('Post', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
)
Post hash tag
sequelize.define('PostHashTag', {
postId: { type: DataTypes.STRING(6), field: 'POST_ID', primaryKey: true },
hashTag: { type: DataTypes.STRING(20), field: 'HASH_TAG', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
}
)
and the query I used is
Post.findAll({
attributes: ['id', 'userId'],
where: {
userId: userId,
id: { $lt: postId }
},
include: [{
model: models.PostHashTag,
attributes: ['hashTag'],
where: {
col1: models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
}]).then(...)
I found an answer by myself... col1:
models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
this should be
userId: models.sequelize.where(models.sequelize.col('POST.userId'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
this will work. The physical names of table and column used in parenthesis

Creating a GraphQLObjectType with an indexable field signature?

I'm currently in the process of transforming a REST API into GraphQL, but I've hit a bit of a snag in one of the endpoints.
Currently, this endpoint returns an object who's keys can be an unlimited set of strings, and whos values all match a certain shape.
So, as a rudimentary example, I have this situation...
// response
{
foo: { id: 'foo', count: 3 },
bar: { id: 'bar', count: 6 },
baz: { id: 'baz', count: 1 },
}
Again, the keys are not known at runtime and can be an unlimited set of strings.
In TypeScript, for example, this sort of situation is handled by creating an interface using an indexable field signature, like so...
interface Data {
id: string;
count: number;
}
interface Response {
[key: string]: Data;
}
So, my question is: Is this sort of thing possible with graphql? How would I go about creating a type/schema for this?
Thanks in advance!
I think that one solution can be usage of JSON.stringify() method
exampleQuery: {
type: GraphQLString,
resolve: (root, args, context) => {
let obj = {
foo: { id: 'foo', count: 3 },
bar: { id: 'bar', count: 6 },
baz: { id: 'baz', count: 1 }
};
return JSON.stringify(obj);
}
}
Then, after retrieving the result of GraphQL query you could use JSON.parse(result) (in case the part performing the query is also written in JavaScript - otherwise you would have to use equivalent method of other language to parse the incoming JSON response).
Disadvantage of such a solution is that you do not have the possibility to choose what fields of obj you want to retrieve from the query, but, as you said, the returning object can have unlimited set of strings that probably are not known on the front end of the application, so there is no need to choose it's keys, am I right?

How do I use More Like This API in Elasticsearch for ruby

I couldn't find any documentation about this at all. Or, maybe I'm missing something. I'm trying to use Elasticsearch's More Like This API with the elasticsearch gem.
I've indexed all documents already.
Here's my code:
require 'elasticsearch'
client = Elasticsearch::Client.new log: true
client.search index: 'movies', body: { query: { match: { description: 'test' } } }
client.search index: 'movies', body: { more_like_this: {
fields: ['description'],
like_text: 'Once upon a time'
} }
I'm getting this error:
Parse Failure [No parser for element [more_like_this]]];
}{[2fk_R7WbTky6UfMCbKPKGA][movies][1]
Try wrapping your more_like_this in query, like so:
client.search index: 'movies', body: {
query: {
more_like_this: {
fields: ['description'],
like_text: 'Once upon a time'
}
}
}
Hope this helps!

Resources