Hello I am implementing elasticsearch using nestjs.
Currently, I am trying to add match keywords according to each condition, but I am having difficulties, so I leave a question.
const { hits } = await this.elasticsearchService.search({
index: 'myindex',
body: {
query: {
bool: {
must: [
{
match: {
type: type.join(' or '),
},
},
keyword && {
query_string: {
query:
'*' + keyword.replace(/ /g, '* AND *') + '*',
},
},
],
},
},
},
});
In the code above, keyword is a variable that may or may not exist.
But I am getting an error in the above code, how should I set the condition?
const query = [];
if(keyword){
query.push({
query_string:{
query : xxx
}
})
}
const { hits } = await this.elasticsearchService.search({
index: 'myindex',
body: {
query: {
bool: {
must: query
},
},
},
});
Related
So it's been a while since I updated my Gatsby blog site, over 2 years and now when I updated all the packages, I noticed the markdown options have changed.
Orginally when I used this code, it would show all my blog post accurately with the correct images etc.
export const query = graphql`
{
allMdx(
filter: { fileAbsolutePath: { regex: "/posts/" } }
sort: { order: DESC, fields: frontmatter___date }
limit: 6
) {
nodes {
frontmatter {
alt
title
path
slug
date(formatString: "MMMM Do, YYYY")
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
id
}
}
}
`
However, now I tried to choose the options based on what I found from graphql that looks similar to my previous options
Here's the new updated code
export const query = graphql`
{
allMdx(
filter: { body: { regex: "/posts/" } }
sort: { order: DESC, fields: frontmatter___date }
limit: 6
) {
nodes {
frontmatter {
alt
title
path
slug
date(formatString: "MMMM Do, YYYY")
image {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
}
id
}
}
}
`
However, this code only displays 2 post on my home page and doesn't show any of the images when I need all 6 to display and showcase all the images.
When I run the queries in graphql it only displays the 2 blog post data so I don't know which option to choose to reshow the same things I had before I updated my site with the new versions of gatsby
Here's my gatsby-config file
plugins: [
`gatsby-plugin-image`,
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
{
resolve: "gatsby-plugin-react-svg",
options: {
rule: {
include: /static/,
},
},
},
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `GatsbyJS`,
short_name: `GatsbyJS`,
start_url: `/`,
background_color: `#f7f0eb`,
theme_color: `#a2466c`,
display: `standalone`,
icon: `src/images/fav-1.png`,
icon_options: {
purpose: `any maskable`,
},
},
},
"gatsby-plugin-offline",
`gatsby-plugin-mdx`,
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
`gatsby-plugin-styled-components`,
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-plugin-sitemap`,
options: {
query: `
{
site {
siteMetadata {
siteUrl
}
}
allSitePage {
nodes {
path
}
}
}`,
resolveSiteUrl: ({ site }) => {
//Alternatively, you may also pass in an environment variable (or any location) at the beginning of your `gatsby-config.js`.
return site.siteMetadata.siteUrl
},
serialize: ({ site, allSitePage }) =>
allSitePage.nodes.map(node => {
return {
url: `${site.siteMetadata.siteUrl}${node.path}`,
changefreq: `weekly`,
priority: 0.7,
}
}),
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `resources`,
path: `${__dirname}/src/resources`,
},
},
// {
// resolve: "gatsby-plugin-page-creator",
// options: {
// path: `${__dirname}/src/posts`,
// },
// },
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.md`, `.mdx`],
gatsbyRemarkPlugins: [{ resolve: "gatsby-remark-images" }],
},
},
{
resolve: `gatsby-plugin-google-fonts`,
options: {
fonts: [`nunito\:400s,700`],
display: "swap",
},
},
{
resolve: `gatsby-plugin-mdx`,
options: {
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
classPrefix: "language-",
inlineCodeMarker: null,
aliases: {},
showLineNumbers: false,
noInlineHighlight: false,
languageExtensions: [
{
language: "superscript",
extend: "javascript",
definition: {
superscript_types: /(SuperType)/,
},
insertBefore: {
function: {
superscript_keywords: /(superif|superelse)/,
},
},
},
],
// Customize the prompt used in shell output
// Values below are default
prompt: {
user: "root",
host: "localhost",
global: false,
},
// By default the HTML entities <>&'" are escaped.
// Add additional HTML escapes by providing a mapping
// of HTML entities and their escape value IE: { '}': '{' }
escapeEntities: {},
},
},
],
},
},
],
UPDATE: For index.js when I use this graph ql query I can finally see my images and the last 6 blog post I set, but not sure what I was supposed to input for the frontmatter so I just left it with empty {}
{
allMdx(
filter: { frontmatter: {} }
sort: { order: DESC, fields: frontmatter___date }
limit: 6
) {
nodes {
id
frontmatter {
title
path
slug
alt
date(formatString: "MMMM Do, YYYY")
image {
childImageSharp {
fluid {
src
}
}
}
}
}
}
}
I tried building a custom graphql query with Strapi as per below:
module.exports = {
definition: `
type flatOnts {
site_name: String
unit_no: String
firstname: String
lastName: String
description: String
isp_name: String
serial_number: String
status: Boolean
}
`,
query: `
flattenOntObj: [flatOnts]
`,
type: {},
resolver: {
Query: {
flattenOntObj: {
description: "Return a flat ont object",
resolverOf: "application::onts.onts.aggregate",
resolver: async (obj, options, ctx) => {
const res = await strapi.api.onts.services.onts.aggregate([
{
$lookup: {
from: "onts",
localField: "ont",
foreignField: "_id",
as: "ont_details",
},
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: ["$ont_details", 0],
},
"$$ROOT",
],
},
},
},
]);
console.log(res);
},
},
},
},
};
However, upon running this in the Graphql playground, I am presented with the "forbidden" error.
Any ideas or pointers?
Appreciate any assistance.
Nevermind, I got it right. I missed a section on the Strapi documentation that explains it: https://strapi.io/documentation/3.0.0-beta.x/concepts/queries.html#custom-queries
In the folder: api/model/services/model.js (my case: api/onts/services/ont.js)
module.exports = {
aggregate: async (aggArray) => {
const res = await strapi.query("ont").model.aggregate(aggArray);
return res;
},
};
and then in api/onts/config/schema.graphql.js:
module.exports = {
definition: `
type flatOnts {
site_name: String
unit_no: String
firstname: String
lastName: String
description: String
isp_name: String
serial_number: String
status: Boolean
}
`,
query: `
flattenOntObj: [flatOnts]
`,
type: {},
resolver: {
Query: {
flattenOntObj: {
description: "Return a flat ont object",
// policies: ["plugins::users-permissions.isAuthenticated"],
resolverOf: "application::onts.onts.find",
resolver: async (obj, options, ctx) => {
const aggregationArray = [
{
$lookup: {
from: "onts",
localField: "ont",
foreignField: "_id",
as: "ont_details",
},
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: ["$ont_details", 0],
},
"$$ROOT",
],
},
},
];
const res = await strapi.api.onts.services.onts.aggregate(
aggregationArray
);
return res;
},
},
},
},
};
I have the following object coming back from db:
{
"total_rows": 200,
"bookmark": "g1AAAABteJzLYWBgYMpgTmEQTM4vTc5ISXIwNDLXMwBCwxyQVCJDUv3___-zMpjc7D8wgEEiCx71eSwgJQ1A6j-GtiwA6MscCg",
"rows": [
{
"id": "51a1ff51b3b4719d05e40ac4bb0d0566",
"objects": {
"0": {
"type": "ipv4-addr",
"value": "192.168.1.10",
"resolves_to_refs": "2"
},
"1": {
"type": "network-traffic"
}
}
],
"counts": {
"created_by_ref": {
"0203a7e6-b174-4af9-812d-ab889816e868": 1,
"0250789a-14c3-4751-b4a0-c017af82b8f1": 1,
"03c63db6-2a84-4627-88be-a83208d524e6": 1,
"05cba3da-11ff-4a7a-aae9-0b1614cd5300": 1,
"fc825d33-26ea-4563-9478-2e1887b87112": 1
},
"file.hashes.MD5": {
"UNDEFINED": 200
},
"file.name": {
"UNDEFINED": 200
},
"ipv4_addr.value": {
"127.0.0.1": 200,
"192.168.1.10": 200
},
"last_observed": {
"1583503380000": 5,
"1583589780000": 9,
"1585749840000": 12
}
},
"num_of_rows": 10
}
I am trying to fit in a graphql schema to the above. I have the following which works paryially:
const graphql = require("graphql");
const { GraphQLObjectType, GraphQLString, GraphQLSchema, GraphQLInt, GraphQLList } = graphql;
const SearchResultType = new GraphQLObjectType({
name: "SearchResult",
fields: ()=>({
total_rows: { type: GraphQLInt },
bookmark: { type: GraphQLString },
//rows: { type: new GraphQLList(GraphQLInt) },
num_of_rows: { type: GraphQLInt }
})
});
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
searchResult:{
type: SearchResultType,
args: { id: { type: GraphQLString } },
resolve(parentValue: any, args: any) {
console.log(args)
return resultMock;
}
}
}
});
module.exports = new GraphQLSchema({
query: RootQuery,
});
The above works for those data types which are defined. However there are some objects in the mockResult above like:
"objects": {
"0": {
"type": "ipv4-addr",
"value": "192.168.1.10",
"resolves_to_refs": "2"
},
"1": {
"type": "network-traffic"
}
or
"counts": {
"created_by_ref": {
"0203a7e6-b174-4af9-812d-ab889816e868": 1,
"0250789a-14c3-4751-b4a0-c017af82b8f1": 1,
"03c63db6-2a84-4627-88be-a83208d524e6": 1,
"05cba3da-11ff-4a7a-aae9-0b1614cd5300": 1,
"fc825d33-26ea-4563-9478-2e1887b87112": 1
So as you see these objects keys are random or at least not guessable until we receive them. Is there any way I can define a sth like this: rows: { type: new GraphQLList(any random object we do not know ) }, as a type in schema below:
const SearchResultType = new GraphQLObjectType({
name: "SearchResult",
fields: ()=>({
total_rows: { type: GraphQLInt },
bookmark: { type: GraphQLString },
rows: { type: new GraphQLList(any random object we do not know ) },
num_of_rows: { type: GraphQLInt }
})
});
You can use the GraphQL JSON Scalar (for example from this implementation). I would not recommend doing this though (in fact years ago I did a talk "GraphQL JSON Scalar considered harmful"). Instead, you might want to transform map-like objects into lists of key-value pairs.
So for example for your counts object you could do the following:
type CreatedByRef {
key: ID
count: Int
}
Object.keys(counts.created_by_ref).map(key => ({
key,
count: counts.created_by_ref[key],
}));
This will change the shape of the result but preserve all the properties of GraphQL.
this is the mutation I want to perform:
const GraphQLAddPlayerResponseMutation = mutationWithClientMutationId({
name: 'AddPlayerResponse',
inputFields: {
cdx: { type: new GraphQLNonNull(GraphQLInt) },
},
mutateAndGetPayload: ({cdx}) => {
var cdxAdded = addplayerResponse(cdx);
console.log("cdxAdded = ",cdxAdded)
return cdxAdded;
}, // what u return on mutateAndGetPayload is available on outputFields
outputFields: {
playerResponse: {
type: GraphQLInt,
resolve: ({cdxAdded}) => {
console.log("outputFields cdxAdded = ",cdxAdded)
return cdxAdded
},
},
viewer: {
type: GraphQLUser,
resolve: () => getViewer(),
},
},
});
Can't figure out what's wrong with the code, it logs on the mutateAndPayload:
mutateAndGetPayload: ({cdx}) => {
var cdxAdded = addplayerResponse(cdx);
console.log("cdxAdded = ",cdxAdded)
return cdxAdded;
},
but I think the outputFields is not evaluated since it's not logging in the console and I get this error:
{
"data": {
"addPlayerResponse": null
},
"errors": [
{
"message": "Cannot create property 'clientMutationId' on number '3'",
"locations": [
{
"line": 4,
"column": 3
}
],
"path": [
"addPlayerResponse"
]
}
]
}
Help?
Replace return cdxAdded; by return { cdxAdded }; (wild guess)
I'm having an issue with mongoosastic in combination with KeystoneJS. I want to search for all the posts of a specific user with a match on the title. I have the following model:
var keystone = require('keystone'),
Types = keystone.Field.Types,
mongoosastic = require('mongoosastic');
User = keystone.list('User');
var Post = new keystone.List('Post');
Post.add({
title: {
type: String,
required: true,
es_indexed: true
},
state: {
type: Types.Select,
options: 'draft, published, archived',
default: 'draft',
es_indexed: true
},
author: {
type: Types.Relationship,
ref: 'User',
es_schema: User,
es_include_in_parent: true,
es_indexed:true
},
publishedDate: {
type: Types.Date,
index: true,
dependsOn: {
state: 'published'
}
},
content: {
extended: {
type: Types.Html,
wysiwyg: true,
height: 400,
es_indexed: true
}
},
});
Post.schema.plugin(mongoosastic, {
hosts: [
process.env.SEARCHBOX_SSL_URL
]
});
Post.defaultColumns = 'title, state|20%, author|20%, publishedDate|20%';
Post.register();
Post.model.createMapping(function(err, mapping) {
if (err) {
console.log('error creating mapping', err);
} else {
console.log('mapping created for Post');
}
});
User.schema.plugin(mongoosastic, {
populate: [
{path: 'author'}
]
});
I tried the approach of "Indexing Mongoose references" (https://github.com/mongoosastic/mongoosastic#indexing-mongoose-references) but I can't get it to work. Elasticsearch is not returning any hits.. My search query:
{
"query": {
"filtered": {
"query": { "match": { "title": "req.query.query" }},
"filter": { "term": { "author": "req.query.userId" }} // or author._id
}
}
}
Can someone provide me the correct Post model configuration & search query? Thanks!