I am using NODE JS with elastic search DB .
I am using this package
https://www.npmjs.com/package/#elastic/elasticsearch
I have this collection in my elastic search DB
[
{
"_index": "products",
"_id": "wZRh3n8Bs9qQzO6fvTTS",
"_score": 1.0,
"_source": {
"title": "laptop issues",
"description": "laptop have issue present in according"
}
},
{
"_index": "products",
"_id": "wpRh3n8Bs9qQzO6fvzQM",
"_score": 1.0,
"_source": {
"title": "buy mobile",
"description": "mobile is in Rs 250"
}
},
{
"_index": "products",
"_id": "w5Rh3n8Bs9qQzO6fvzTz",
"_score": 1.0,
"_source": {
"title": "laptop payment",
"description": "laptop payment is given in any way"
}
}
]
now I am planning to fetch data from elastic DB . when I am passing "LAP" or "lap" . it is giving me blank array or [] array why ? "lap" is present in all object
I am doing like that
const result= await client.search({
index: 'products',
query: {
match_phrase: {
description: "lap"
}
}
where I am doing wrong . I need all result where lap keywords is present
Match query is not working because you are trying to search partial character of laptop term.
You can use Prefix Query for single term like below:
{
"query": {
"prefix": {
"title": {
"value": "lap"
}
}
}
}
If you want to search for phrase then you can use Phrase Prefix Query:
{
"query": {
"match_phrase_prefix": {
"title": "lap"
}
}
}
If you want to match only some of the word from query then you can use match query with operator set to or.
POST querycheck/_search
{
"query": {
"match": {
"title": {
"query": "i have issues",
"operator": "or"
}
}
}
}
Related
Given the ElasticSearch document below:
{
"_id": "3330481",
"_type": "user",
"_source": {
"id": "3330481",
"project": "Cool_Project_One"
}
}
I'm building a UI component that will auto suggest to the user all the values in "project" field base on his text input
For example:
As the user types "Cool" i would like to show him all the values from the "project" field that starts with "Cool"
I've create this aggregation:
"aggs": {
"projects": {
"terms": {
"field": "project",
"size": 2
}
}
}
which returns me a list with all the values for the project field, but i can't understand how should i find only the values that are matching to a certain expression.
I've found this answer that shows how to add filter, but it seems that the filter returns only exact matches as i tried to do that:
{
"aggs": {
"projects": {
"filter": {
"term": {
"project": "Cool"
}
},
"aggs": {
"terms": {
"field": "project",
"size": 2
}
}
}
}
}
And it didn't worked.
Any help would be appreciated
Some notes:
term query will look for exact matches (casing included, if you want something more flexible you can use a regular "match" query
In general, you want to add the filter in the query, no aggregations
You can use aggregations to group by category type fields, but you can use regular queries to match against title type fields
I would suggest to use a suggestion field type for this, to also capture prefixes (proj in project por example).
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-as-you-type.html
I just seen you have _type defined, so probably you are using an old version of Elasticsearch, and search_as_you_type is relatively new. I will add some examples with both query and aggs:
Mappings for search_as_you_type, text, and keyword fields :
PUT test_suggestions
{
"mappings": {
"properties": {
"project": {
"type": "text",
"fields": {
"suggestions": {
"type": "search_as_you_type"
},
"keyword": {
"type": "keyword"
}
}
}
}
}
}
Indexing document
POST test_suggestions/_doc
{
"project": "Cool Project"
}
search_as_you_type query, supports prefixes out of the box:
GET test_suggestions/_search
{
"query": {
"multi_match": {
"query": "coo",
"type": "bool_prefix",
"fields": [
"project",
"project._2gram",
"project._3gram"
]
}
},
"aggs": {
"project_categories": {
"terms": {
"field": "project.keyword",
"size": 10
}
}
}
}
Regular query, case insensitive and you can write just a portion of the field and will work
GET test_suggestions/_search
{
"query": {
"match": {
"project": "Cool"
}
},
"aggs": {
"project_categories": {
"terms": {
"field": "project.keyword",
"size": 10
}
}
}
}
Bonus: prefix search without search_as_you_type or setting up ngrams:
GET test_suggestions/_search
{
"query": {
"match_phrase_prefix": {
"project": "coo"
}
},
"aggs": {
"project_categories": {
"terms": {
"field": "project.keyword",
"size": 10
}
}
}
}
I'm making a kanban task management app and I'm trying to remove a task with the _id: req.params.id which has the value of 62fa5ae05778ec97bc6ee23a. I tried the following:
const task = await Board.findOneAndUpdate(
{
"columns.tasks._id": req.params.id,
},
{ $pull: { "columns.$.tasks.$._id": req.params.id } },
{ new: true }
);
But I get the error Too many positional (i.e. '$') elements found in path'columns.$.tasks.$._id'
I searched for a while and came across arrayFilters from the docs but I'm struggling a lot to understand how to implement it for this particular need.
{
"_id": "62fa5aa25778ec97bc6ee231",
"user": "62f0eb5ebebd0f236abcaf9d",
"name": "Marketing Plan",
"columns": [
{
"name": "todo",
"_id": "62fa5aa25778ec97bc6ee233",
"tasks": [
{
"title": "Task Four",
"description": "This is task four",
"subtasks": [
{
"name": "wash dshes",
"completed": false,
"_id": "62fa5ae05778ec97bc6ee23b"
},
{
"name": "do homework",
"completed": false,
"_id": "62fa5ae05778ec97bc6ee23c"
}
],
"_id": "62fa5ae05778ec97bc6ee23a"
}
]
},
{
"name": "doing",
"_id": "62fa5aa25778ec97bc6ee234",
"tasks": []
},
{
"name": "done",
"_id": "62fa5aa25778ec97bc6ee235",
"tasks": []
}
],
"__v": 0
}
You need to use $[] positional operator in order to pull from the nested array. Try running this query:
db.Board.updateOne({
"_id" : "62fa5aa25778ec97bc6ee231",
}, {
$pull: { 'columns.$[].tasks': { '_id': '62fa5ae05778ec97bc6ee23a' } }
});
Please, help me. I cant find information about how do this.
I have got this code. It load all products with all relations. One of relations is product item. In product item entity I have got price column.
How I can get minimal product item price without get in my response array of product items?
const { skip, take } = pagination;
const query = this.createQueryBuilder('product');
query.where('product.shop = :id AND product.blocked = FALSE', {
id: shop.id,
});
if (skip) {
query.offset(Number(skip));
}
if (take) {
query.limit(Number(take));
}
query.leftJoin('product.info', 'info');
query.leftJoin('product.avatar', 'avatar');
// load product items
query.leftJoin('product.productItem', 'item');
query.select([
'product.id',
'product.path',
'info.name',
'info.description',
'info.info',
'info.lang',
'avatar.path',
'avatar.type',
'item.price'
]);
const [list, amount] = await query.getManyAndCount();
Now i have got:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"productItem": [
{
"price": 1000
},
{
"price": 500
},
{
"price": 300
},
{
"price": 2000
},
{
"price": 3000
}
]
}
]
}
........
But I need:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"minProductItemPrice": 300
}
]
}
Pls help me
You can find the answer for this on Stackoverflow already.
Here is a similar question Typeorm select max with specific column
Basically, getManyAndCount() method that you are using is useful when fetching entities. In your case, you are trying to obtain an aggregate value encompassing multiple entities.
You need to make separate selection, like so
query.select("MIN(item.price)", "min");
and then get the result with
return query.getRawOne();
I would like to get the opposite GraphQL query field:
which mean the query string will not appeal in the result, while not inside the query string will appeal in the result.
Because there are varties of json recorders, I can not manually write opposite query. Any way to write opposite query automatically?
for example, I have JSON like:
{
"data": {
"source": "AWS",
"hero": {
"version": "my version",
"name": "R2-D2",
"friends": [
{
"attribute": "like something",
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
I have query
{
source,
hero {
name
friends {
attribute
}
}
}
I like to get a result:
{
"data": {
"hero": {
"version": "my version",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
Which the query fields not in the query will appear in the result, while the query fields in the query will not inside the result.
How to do these operations in JavaScript? Can you give me an example?
You only get the fields you include in the Query if you want to get whats not in the query then write another query for the fields not in the original query.
At its simplest, GraphQL is about asking for specific fields on objects.
https://graphql.org/learn/queries/
Query:
{
hero {
version
friends {
name
}
}
}
Result:
{
"data": {
"hero": {
"version": "my version",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
Update from comments:
Your question is more of how to Dynamically Generate GraphQL Queries?
In this case you could use fragments, but you would still have to write multiple queries.
Fragments let you construct sets of fields, and then include them in queries where you need to.
https://graphql.org/learn/queries/#fragments
I have an array of items in my database, some of these items have an array called relatedItems, which are basically an array of IDs, and these IDs could match some of the items inside the same document. I can run populate to transform the array of IDs into an array of objects, where each object is the populated item with the matched ID. But I also want to remove those items from the main array of items. Here is the example of my data structure:
{
"data": {
"getItems": [
{
"title": "item 09",
"_id": "5a56215426004a22c17ba733",
"relatedItems": ["5a5621a526004a22c17ba773", "5a56214b26004a22c17ba72a", "5a56215326004a22c17ba732", "5a56215726004a22c17ba735"]
},
{
"title": "item 10",
"_id": "5a56215726004a22c17ba735",
"thumbnail": {
"Key": ".../5a56215726004a22c17ba735/thumbnail.jpg"
}
},
{
"title": "item 11",
"_id": "5a56215326004a22c17ba732",
"thumbnail": {
"Key": ".../5a56215326004a22c17ba732/thumbnail.jpg"
}
},
{
"_id": "5a56216b26004a22c17ba747",
"relatedItems": []
},
{
"_id": "5a56216c26004a22c17ba748",
"relatedItems": []
}
]
}
}
And I am running the following code to populate the data:
let items = await ItemModel.find({ category }).limit(limit).sort({ itemOrder: 1 })
.populate({path: 'relatedItems', select: '_id thumbnail'}).sort({ itemOrder: 1 });
But as you know, after populating, and I am going to end up having duplicate items (one copy in the related items array and one in the main array) like so:
{
"data": {
"getItems": [
{
"title": "item 09",
"_id": "5a56215426004a22c17ba733",
"relatedItems": [
"_id": "5a5621a526004a22c17ba773",
"thumbnail": {
"Key": ".../5a5621a526004a22c17ba773/thumbnail.jpg"
}
},
{
"_id": "5a56214b26004a22c17ba72a",
"thumbnail": {
"Key": ".../5a56214b26004a22c17ba72a/thumbnail.jpg"
}
},
{
"title": "item 11",
"_id": "5a56215326004a22c17ba732",
"thumbnail": {
"Key": ".../5a56215326004a22c17ba732/thumbnail.jpg"
}
},
{
"title": "item 10",
"_id": "5a56215726004a22c17ba735",
"thumbnail": {
"Key": ".../5a56215726004a22c17ba735/thumbnail.jpg"
}
}
]
},
{
"title": "item 10",
"_id": "5a56215726004a22c17ba735",
"thumbnail": {
"Key": ".../5a56215726004a22c17ba735/thumbnail.jpg"
}
},
{
"title": "item 11",
"_id": "5a56215326004a22c17ba732",
"thumbnail": {
"Key": ".../5a56215326004a22c17ba732/thumbnail.jpg"
}
},
{
"_id": "5a56216b26004a22c17ba747",
"relatedItems": []
},
{
"_id": "5a56216c26004a22c17ba748",
"relatedItems": []
}
]
}
}
I would like to remove the copy from the main array, and currently, I have accomplished it via the following code:
let items = await ItemModel.find({ category }).limit(limit).sort({ itemOrder: 1 })
.populate({path: 'relatedItems', select: '_id thumbnail'}).sort({ itemOrder: 1 });
Promise.all(items.map(async item => {
if (item.relatedItems && item.relatedItems.length > 0) {
Promise.all(item.relatedItems.map(async relatedItem => {
related.push(relatedItem._id);
}));
}
}));
items = items.filter(item => !JSON.stringify(related).includes(item._id));
And it works, but I am wondering if there is a faster/safer or more MongoDB native way to do this?
Edit
One important downside to using my filter method is that .limit(limit) does not work properly anymore since the array will be trimmed down if it finds duplicates, the workaround is using .slice(0, limit) on the final array after filtering, but doesn't sound like it's the best way. Also I kinda feel I am going to run into some issues if I decide to add pagination to it too.