Algolia Instant search default order by state (`live`, 'published', 'draft') - algolia

I'm trying to fetch Algolia results in particular order, hits have state column, and state values can be live/published/draft
Data in algolia
{ name: Post1, state: draft},
{ name: Post2, state: published},
{ name: Post3, state: live}
Expected Result
Default order should be, first live then published and then show draft
{ name: Post3, state: live},
{ name: Post2, state: published},
{ name: Post1, state: draft}

Algolia doesn't support sorting by an enumerated type like this. Instead, in search, it is more common to use the state as a facet and allow users to filter results based on the enumerated value.
You could simulate the enumerated sort by performing a multi-index query with three separate queries to the same index with each of the state values as a filter, then display the results for each state.

Related

Mongodb create index for boolean and integer fields

user collection
[{
deleted: false,
otp: 3435,
number: '+919737624720',
email: 'Test#gmail.com',
name: 'Test child name',
coin: 2
},
{
deleted: false,
otp: 5659,
number: '+917406732496',
email: 'anand.satyan#gmail.com',
name: 'Nivaan',
coin: 0
}
]
I am using below command to create index Looks like for string it is working
But i am not sure this is correct for number and boolean field.
db.users.createIndex({name:"text", email: "text", coin: 1, deleted: 1})
I am using this command to filter data:
db.users.find({$text:{$search:"anand.satya"}}).pretty()
db.users.find({$text:{$search:"test"}}).pretty()
db.users.find({$text:{$search:2}}).pretty()
db.users.find({$text:{$search:false}}).pretty()
string related fields working. But numeric and boolean fields are not working.
Please check how i will create index for them
The title and comments in this question are misleading. Part of the question is more focused on how to query with fields that contain boolean and integer fields while another part of the question is focused on overall indexing strategies.
Regarding indexing, the index that was shown in the question is perfectly capable of satisfying some queries that include predicates on coin and deleted. We can see that when looking at the explain output for a query of .find({$text:{$search:"test"}, coin:123, deleted: false}):
> db.users.find({$text:{$search:"test"}, coin:123, deleted: false}).explain().queryPlanner.winningPlan.inputStage
{
stage: 'FETCH',
inputStage: {
stage: 'IXSCAN',
filter: {
'$and': [ { coin: { '$eq': 123 } }, { deleted: { '$eq': false } } ]
},
keyPattern: { _fts: 'text', _ftsx: 1, coin: 1, deleted: 1 },
indexName: 'name_text_email_text_coin_1_deleted_1',
isMultiKey: false,
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'backward',
indexBounds: {}
}
}
Observe here that the index scan stage (IXSCAN) is responsible for providing the filter for the coin and deleted predicates (as opposed to the database having to do that after FETCHing the full document.
Separately, you mentioned in the question that these two particular queries aren't working:
db.users.find({$text:{$search:2}}).pretty()
db.users.find({$text:{$search:false}}).pretty()
And by 'not working' you are referring to the fact that no results are being returned. This is also related to the following discussion in the comments which seemed to have a misleading takeaway:
You'll have to convert your coin and deleted fields to string, if you want it to be picked up by $search – Charchit Kapoor
So. There is no way for searching boolean or integger field. ? – Kiran S youtube channel
Nope, not that I know of. – Charchit Kapoor
You can absolutely use boolean and integer values in your query predicate to filter data. This playground demonstrates that.
What #Charchit Kapoor is mentioning that can't be done is using the $text operator to match and return results whose field values are not strings. Said another way, the $text operator is specifically used to perform a text search.
If what you are trying to achieve are direct equality matches for the field values, both strings and otherwise, then you can delete the text index as there is no need for using the $text operator in your query. A simplified query might be:
db.users.find({ name: "test"})
Demonstrated in this playground.
A few additional things come to mind:
Regarding indexing overall, databases will generally consider using an index if the first key is used in the query. You can read more about this for MongoDB specifically on this page. The takeaway is that you will want to create the appropriate set of indexes to align with your most commonly executed queries. If you have a query that just filters on coin, for example, then you may wish to create an index that has coin as its first key.
If you want to check if the exact string value is present in multiple fields, then you may want to do so using the $or operator (and have appropriate indexes for the database to use).
If you do indeed need more advanced text searching capabilities, then it would be appropriate to either continue using the $text operator or consider Atlas Search if the cluster is running in Atlas. Doing so does not prevent you from also having indexes that would support your other queries, such as on { coin: 2 }. It's simply that the syntax for performing such a query needs to be updated.
There is a lot going on here, but the big takeaway is that you can absolutely filter data based on any data type. Doing so simply requires using the appropriate syntax, and doing so efficiently requires an appropriate indexing strategy to be used along side of the queries.

MongoDB Atlas - Boost search score from external list of words

I use MongoDB Atlas' full-text search which can boost the search score (how relevant a result is for that particular search query) by specifying the path that should be weighed more. Example:
text: {
query: query,
path: ["title"],
allowAnalyzedField: true,
score: { boost: { value: 2 } },
}
This will give results where the query appears in the "title" property a higher weight.
I want to do the same, but instead of specifying a path, I want to check if the query appears in an array of strings that I prepare beforehand. I want to weigh these words/phrases higher. How can I do that?

How do you filter Algolia Results and omit a specific objectID

I'm trying to filter algolia results and want to use the name of a product to find similar products in our database. I would prefer to ignore the current product so, in the case no results are found, the removeWordsIfNoResults option will be used.
I'm using the Ruby api.
This is basically what I'm trying but it is not working. Is it possible to filter out a specific objectID?
Product.raw_search("Men's Bridge & Burn Camden Steel Blue",
{ :hitsPerPage => 10,
:page => 0,
:attributesToRetrieve => "objectID",
:filters => "objectID != '65411'",
:removeWordsIfNoResults => 'lastWords'
}
)
objectID is a specific attribute in Algolia that is always a string value and cannot be added to the attributesForFaceting .
However, if you're filling it with the ids you have in your database, you can index another attribute (let's say id) with the same value.
Numerical value
As an numerical value, you can directly filter on it using Algolia. However, since you'll only be using the != operator, I recommend you to declare it in the numericAttributesToIndex list with an equalOnly modifier:
index.set_settings({
numericAttributesToIndex: %w(equalOnly(id))
})
At query time, you can pass it as you did in your example if you remove the quotes around the value:
index.raw_search('Product title', {
filters: 'id!=65411'
# Your other parameters
})
String value
With a string value, you want to add it to your attributesForFaceting :
index.set_settings({
attributesForFaceting: %w(id)
})
Then query it like so:
index.raw_search('Product title', {
filters: 'id:-65411'
# Your other parameters
})
(The - for exclusion is described in the facetFilters documentation)

Select the last document from mongo collection in meteor

I want the latest document in the query. Below I'm getting those documents whose name is coming from the variable 'personalFullName, then sorting them by a field called 'RecordID' (this field has higher numbers as later date entries), then grab the last one. I want the latest (the one with the largest RecordID number) entry in this query:
Programs.find({ FullName: personalFullName }, { sort: { RecordID: 1 }, limit: 1}).fetch().pop();
I'm getting an error that it's exceeding the call stack size.
If you are comfortable using the meteorhacks:aggregate package then you could always publish the item(s) you want using the mongo aggregate pipeline, perhaps something like this (code is coffeescript):
Meteor.publish 'latestPrograms', (personalFullName)->
return unless personalFullName?
check personalFullName, String
pipeline = [
{$match:{'Fullname': personalFullName}}
{$sort: {'RecordID': 1}}
{$group:{'_id':{Fullname: '$Fullname'}, RecordID:{$last:'$RecordID'}}}
{$limit:1}
]
#added 'latestPrograms', Random.id(), item for item in programs.aggregate pipeline
#ready()
You can then grab the data by subscribing to the latestPrograms pseudo collection. Here is an example using a iron router route:
Router.route '/home',
name: 'home'
template:'homepage'
waitOn:->
Meteor.subscribe 'latestPrograms', personalFullName
data:->
{latestPrograms: latestPrograms.find()}

Querying array of ObjectIds using mongoose

The users table contains an items array which is just a collection of Item ObjectId's.
Users
{
state: 'active',
items: [ObjectId("4ecc05e55dd98a436ddcc47c"), ObjectId("4ecc05e55dd98a436ddcc47d")]
}
Items
{
name: 'weapon',
creator: 'mark'
}
I want to write a query that finds all users which have an item with creator 'mark'. Is that possible in one query? I tried something like this but it does not work.
{
'items.creator': 'mark
};
Firstly, you need to have the items collection either as embedded or reference. With this structure in mind, we can write the query as
db.Users.find({"items.creator" : 'mark'})