Add a record to an Algolia Index only if it does not exists - algolia

I was wondering how can i POST in a single request (without fetching results for the given attribute) a pretty simple record to an Algolia Index without creating repeated instances.
e.g:
category: {
name: String // This should be unique
}

There isn't such "addObject if not exists" feature based on the record content but if you use the category name as the objectID of your record; the second time you'll add the object, it will just replace the previous instance.
{
objectID: "mycategoryname",
moreattributes: "if needed",
[...]
}
Would that work?

Related

Nested Hasura GraphQL Upsert mutation is there a way to stop nesting on conflict?

I use Hasura and I have a social-network like situation.
In which I have a "User" object and a "Feed" object.
Every user has a feed.
I have a relationship from user.id to feed.id.
The relevant mutation is UpsertUserDetails as follows:
mutation UserDetailsUpsert(
$email: String!
$picture: String
) {
insert_users_one(
object: {
email: $email
feed: { data: {} }
picture: $picture
}
on_conflict: { constraint: users_tid_email_key, update_columns: [picture] }
) {
id
}
}
So when I create a new user it also creates a feed for it.
But when I only update user details I don't want it to create a new feed.
I would like to stop the upsert from going through to relationships instead of the above default behavior.
and according to this manual I don't see if its even possible: https://hasura.io/docs/latest/graphql/core/databases/postgres/mutations/upsert.html#upsert-in-nested-mutations
To allow upserting in nested cases, set update_columns: []. By doing this, in case of a conflict, the conflicted column/s will be updated with the new value (which is the same values as they had before and hence will effectively leave them unchanged) and will allow the upsert to go through.
Thanks!
I'd recommend that you design your schema such that bad data cannot be entered in the first place. You can put partial unique indices on the feed table in order to prevent duplicate feeds from ever being created. Since you have both users and groups you can implement it with 2 partial indices.
CREATE UNIQUE INDEX unique_feed_per_user ON feed (user_id)
WHERE user_id IS NOT NULL;
CREATE UNIQUE INDEX unique_feed_per_group ON feed (group_id)
WHERE group_id IS NOT NULL;

How can I create a relation in Strapi if I don't know the id of the field?

I am creating a collection of judges and courthouses. Every judge will be assigned to one courthouse. I have set up my relation to be that courthouse has many judges
I am attempting to do this programmatically when the app loads. I have a function that is able to populate all the fields in judge except the relation to courthouse. My function uses the Strapi API like this
const judge = await strapi.query('judge').create({
name: data[i].name,
},
{
courthouse: data[i].courthouse_name // here is where I think the relation is created
}
)
I am passing in a string that has the name of courthouse, because I don't know the ID of the courthouse in the Courthouse collection.
My question is it possible to create a relation to another collection by anything other than an ID? How can I create a relation to a courthouse by its name?
I couldn't find a way around building a relationship between two models without the ID, so I created a custom solution using the Strapi lifecycle hooks
Essentially what I did I utilized the beforeCreate lifecycle hook to query and find the courthouse that matches the name like this:
// judges.js
async beforeCreate(result, data) {
const courthouse = await strapi.query('courthouse').find(
{courthouse_name:data.courthouse}
); // returns the courthouse that matches the name
result['courthouse'] = courthouse[0].id; // populates the relational field with the
// ID of the courthouse
}
The response object contained the courthouse's ID and I manipulated the data that is being sent to the create command like this:
const judge = await strapi.query('judge').create({
name: data[i].name,
courthouse: data[i].courthouse_name
})
The result is an object that looks like this:
{name: 'Garfield Lucas, courthouse: 7463987}

MongoDB Complex Query with Java

We have following structure in MongoDB documents.
{
"id":"1111",
"keys":[
{
"name":"Country",
"value":"USA"
},
{
"name":"City",
"value":"LongIsland"
},
{
"name":"State",
"value":"NewYork"
}
]
}
Now using Springframework Query object, I figured out a way to pull the details using below syntax
query.addCriteria(
Criteria.where("keys.value").is(countryparam).
andOperator(
Criteria.where("keys.value").is(stateparam)
)
);
Two issue with this query model.
First issue is it is irrelevant if countryparam and stateparam are actually meant to match Country key name and State key name respectively. If just the values matches, the query returns the document. Means, if I have Country and City params, this just works if user passes Country and City values, even if they are swapped. So how can I exactly compare City to cityparam and State to Stateparam?
More complexity is if I have to extract the document basing on multiple key value pairs, I should be correspondingly able to match key name with respective value and query the document. How can I do this?
Thanks in advance!

Meteor: return subset of attributes from Mongo

Im querying Mongo to get the user item, but I only want to pass through a subset of the info to the template. My current solution is this:
var returnUsers = [];
var users = Meteor.users.find().fetch();
for (var i = 0; i < users.length; i++) {
returnUsers.push(users[i].profile);
}
console.log(returnUsers);
return returnUsers;
But I'm losing the iterator. Ideally I want to just return the profile object of each user. How do you do that?
There is little point in doing this on the client. Returning a cursor with fields you don't end up using from minimongo is normally just as fast or faster than filtering fields out in javascript.
Especially for the Users collection you want to filter out the extra fields in your publication from the server. For example:
Meteor.publish('allUsers',function(){
return Meteor.users.find({},{ fields: { profile: 1 }});
});
This will publish the profile data and the _id for each user. Then when you do
Meteor.users.find({});
on the client you will only get the profile data and _id without any need to do extra filtering.
Note that the fields option only allows you to define a set of fields to include or exclude together. You cannot mix include and exclude:
{ fields: { key1: 0, key2: 1 }}
will fail.
There is no security benefit to filtering fields on the client either. The user has full access to the published collection from the console.
Seeing as you want to keep cursor as per comment in previous answer remove the fetch as this turns it into an array not a cursor and add fields like below
return Meteor.users.find({},{fields:{profile:1}});
This won't give you only profile but will also return the id as this is always sent regardless of the fields specified to return.
use `map`
var profiles=Meteor.users.find().map(function(a){return a.profile})

Multi level MongoDB object querying by key

If you only know the key name (say "nickname"), but not the exact path to that key in the object.
e.g. nickname may be at the first level like:
{"nickname":"Howie"}
or at the second level:
{"user":{"nickname":"Howie"}}
Is it possible to query for nickname equal "Howie" that would return both documents?
Unfortunately there is no wild card that allows you to search for a field at any level in the db. If the position is not relevant and you can modify the document structure you have 2 choices here. You can store your document as
{ fieldname:"nickname", value : "Howie" }
{ fieldname:"user/nickname", value: "Howie" }
You can then query using
db.so.find({fieldname:/nickname/, value:"Howie"})
Alternatively you can store as
db.so.insert({value:"Howie", fieldpath:["nickname"]})
db.so.insert({value:"Howie", fieldpath:["user", "nickname"]})
The advantage with the second approach is that you can now index {fieldpath:1, value:1} and a query on it such as
db.so.find({fieldpath:"nickname", value:"Howie"})
will be an indexed query.