So I am using Algolia.com to index users for quick searching.
An example object in index:
{
id: 1,
username: "john.doe",
name: "John Doe",
attributes: {
gender: "male",
hair_color: "blonde",
eye_color: "blue",
height: 165
}
}
I'd like to filter results by a specific attribute (object key) in the attributes object.
I thought maybe using facetFilters would do the job, but I am unable to get it working.
I have tried many variances of this code:
user_index.search('', {
facets: '*',
facetFilters: ['attributes.hair_color:blonde', 'attributes.eye_color:blue']
}, function(error, data) {
console.log(error, data);
});
-- / --
user_index.search('', {
facets: '*',
facetFilters: ['hair_color:blonde']
}, function(error, data) {
console.log(error, data);
});
Please find the documentation here: https://www.algolia.com/doc/javascript
Just in order to be able to mark this question as answered :
You should add attributes.hair_color to your attributesForFaceting (Display tab in your index dashboard)
You should be able to easily just do
user_index.search('', {
facetFilters: 'attributes.hair_color:blonde'
}, function () {
console.log(arguments);
});
to search.
Sounds like using facet filters is the best way to achieve what you're looking for. The easiest way is to handle those filters is probably to use the Javascript Helper https://github.com/algolia/algoliasearch-helper-js#filtering-results.
You would then only need to call
helper.addFacetRefinement('hair_color', 'blonde').search();
Related
I need to retrieve just some columns of relations in typeorm query.
I have an entity Environment that has an relation with Document, I want select environment with just url of document, how to do this in typeorm findOne/findAndCount methods?
To do that you have to use a querybuilder, here's an example:
return this.createQueryBuilder('environment') // use this if the query used inside of your entity's repository or getRepository(Environment)...
.select(["environment.id","environment.xx","environment.xx","document.url"])
.leftJoin("environment.document", "document")
.where("environment.id = :id ", { id: id })
.getOne();
Sorry I can't add comment to post above. If you by not parsed data mean something like "environment.id" instead of "id"
try this:
return this.createQueryBuilder("environment")
.getRepository(Environment)
.select([
"environment.id AS id",
"environment.xx AS xx",
"document.url AS url",
])
.leftJoin("environment.document", "document")
.where("environment.id = :id ", { id: id })
.getRawOne();
Here is the code that works for me, and it doesn't require using the QueryBuilder. I'm using the EntityManager approach, so assuming you have one of those from an existing DataSource, try this:
const environment = await this.entityManager.findOne(Environment, {
select: {
document: {
url: true,
}
},
relations: {
document: true
},
where: {
id: environmentId
},
});
Even though the Environment attributes are not specified in the select clause, my experience is that they are all returned in the results, along with document.url.
In one of the applications that I'm working on, I have the need to bring back attributes from doubled-nested relationships, and I've gotten that to work in a similar way, shown below.
Assuming an object model where an Episode has many CareTeamMembers, and each CareTeamMember has a User, something like the code below will fetch all episodes (all attributes) along with the first and last name of the associated Users:
const episodes = await this.entityManager.find(Episode, {
select: {
careTeamMembers: {
id: true, // Required for this to work
user: {
id: true,
firstName: true,
lastName: true,
},
}
},
relations: {
careTeamMembers: {
user: true,
}
},
where: {
deleted: false,
},
});
For some reason, I have to include at least one attribute from the CareTeamMembers entity itself (I'm using the id) for this approach to work.
I'm currently using AngularJS, and the backend is using NodeJS and Express. I use Mongoose to access the database. I'm trying to figure how to add attributes to nested objects and I can't for the life of me find out how to do it anywhere on the web.
My Schema looks like this:
{
id: {
type: String
},
involved: {
type: String
},
lastMsgRead: Object
}
lastMsgRead will look something like this:
{
user1: "somestringblahblah",
user2: "someotherstring",
}
and so on.
My question is, how would I update lastMsgRead with Mongoose to add another attribute to it, such as adding user3 so it now looks like:
{
user1: "somestringblahblah",
user2: "someotherstring",
user3: "anotherstring"
}
The entire document would like this after the update:
{
id: "string",
involved: "string",
lastMsgRead: {
user1: "somestringblahblah",
user2: "someotherstring",
user3: "anotherstring"
}
}
Edit:
After I add the attribute, how would I then update it in the future?
You can use .dot notation to update in nested object
db.collection.update(
{ },
{ "$set": { "lastMsgRead.user3": "anotherstring" } }
)
in mongoose 5.1.0 and up you can approach this with the MongooseMap.
You can define it in the schema as followed:
{
id: {
type: String
},
involved: {
type: String
},
lastMsgRead: {
type: Map,
of: String
}
}
you can then add a new value by .set(key, value)
myDoc.lastMsgRead.set(key, value)
and get a value by .get(key)
myDoc.lastMsgRead.get(key)
I'm building a Thesaurus app, and for this question, the key note is that i'm adding a list of synonyms(words that have the same meaning) for a particular word(eg - "feline", "tomcat", "puss" are synonyms of "cat")
I have a Word object, with a property - "synonyms" - which is an array.
I'm going to add an array of synonyms to the Word synonyms property.
According to the MongoDb documentation see here, the only way to append all the indexes of an array to a document's array property at once is to try the following:
db.students.update(
{ _id: 5 },
{
$push: {
quizzes: {
$each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
}
}
}
)
Let's re-write that solution to suit my data, before we venture further.
db.words.update(
{ baseWord: 'cat' },
{
$push: {
synonyms: {
$each: [ { _id: 'someValue', synonym: 'feline' }, { _id: 'someValue', synonym: 'puss' }, { _id: 'someValue', synonym: 'tomcat' } ],
}
}
}
)
Nice and concise, but not what i'm trying to do.
What if you don't know your data beforehand and have a dynamic array which you'd like to feed in?
My current solution is to split up the array and run a forEach() loop, resulting in an array being appended to the Word object's synonyms array property like so:
//req.body.synonym = 'feline,tomcat,puss';
var individualSynonyms = req.body.synonym.split(',');
individualSynonyms.forEach(function(synonym) {
db.words.update(
{ "_id": 5 },
{ $push: //this is the Word.synonyms
{ synonyms:
{
$each:[{ //pushing each synonym as a Synonym object
uuid : uuid.v4(),
synonym:synonym,
}]
}
}
},{ upsert : true },
function(err, result) {
if (err){
res.json({ success:false, message:'Error adding base word and synonym, try again or come back later.' });
console.log("Error updating word and synonym document");
}
//using an 'else' clause here will flag a "multiple header" error due to multiple json messages being returned
//because of the forEach loop
/*
else{
res.json({ success:true, message:'Word and synonyms added!' });
console.log("Update of Word document successful, check document list");
}
*/
});
//if each insert happen, we reach here
if (!err){
res.json({ success:true, message:'Word and synonyms added!.' });
console.log("Update of Word document successful, check document list");
}
});
}
This works as intended, but you may notice and issue at the bottom, where there's a commented out ELSE clause, and a check for 'if(!err)'.
If the ELSE clause is executed, we get a "multiple headers" error because the loop causes multiple JSON results for a single request.
As well as that, 'if(!err)' will throw an error, because it doesn't have scope to the 'err' parameter in the callback from the .update() function.
- If there was a way to avoid using a forEach loop, and directly feed the array of synonyms into a single update() call, then I can make use of if(!err) inside the callback.
You might be thinking: "Just remove the 'if(!err)' clause", but it seems unclean to just send a JSON response without some sort of final error check beforehand, whether an if, else, else if etc..
I could not find this particular approach in the documentation or on this site, and to me it seems like best practice if it can be done, as it allows you to perform a final error check before sending the response.
I'm curious about whether this can actually be done.
I'm not using the console, but I included a namespace prefix before calling each object for easier reading.
There is not need to "iterate" since $each takes an "array" as the argument. Simply .map() the produced array from .split() with the additional data:
db.words.update(
{ "_id": 5 },
{ $push: {
synonyms: {
$each: req.body.synonym.split(',').map(synonym =>
({ uuid: uuid.v4, synonym })
)
}
}},
{ upsert : true },
function(err,result) {
if (!err){
res.json({ success:true, message:'Word and synonyms added!.' });
console.log("Update of Word document successful, check document list");
}
}
);
So .split() produces an "array" from the string, which you "transform" using .map() into an array of the uuid value and the "synonym" from the elements of .split(). This is then a direct "array" to be applied with $each to the $push operation.
One request.
I am trying to use the filter for Magento SOAP v2 (Magento 1) but my code doesn't seem to work. I tried several ways of building to object with arrays but none of them seems to affect the returning results.
Can anybody explain me the right way to do that?
What I want to do is pull in all invoices but for example with a specific invoice ID or date.
Link to official Magento documentation:
http://devdocs.magento.com/guides/m1x/api/soap/sales/salesOrderInvoice/sales_order_invoice.list.html
This is my current code:
const filter = {
'complex_filter': [
{
key: 'invoice_id',
value: {
key: 'eq',
value: '94'
}
}
]
};
client.salesOrderInvoiceList(res, filter, function(error, result) {
console.log(result.result)
});
In the above example I only tried to use the filter for the invoice ID but I also tried with the date but that didn't work out either.
Thanks in advance.
For me, the easiest solution was to just map exactly to what the XML document would look like if this was done by PHP SoapClient.
const args = {
sessionId: session_id,
storeView: store_id,
filters: {
complex_filter: {
complexObjectArray: {
key: 'created_at',
value: {
key: 'from',
value: '2017-01-01'
}
}
}
}
};
client.catalogProductList(args, (err, result) => { ... }
I am currently using StrongLoop as my API backend server and Mongodb as data storage engine.
Let's say there is a collection called article. It has two fields title, and content. And there are two frontend pages to display a list of articles and view a single article.
Obviously the data list page only need title field and the view page need both. Currently the GET method of StrongLoop API return all fields including content. It cost extra traffic. Is there any way that can just return specific field?
Mongodb support projection in find() method for this. How can I do the same thing by StrongLoop?
Have you taken a look at the filters offered. http://docs.strongloop.com/display/LB/Querying+models
Query for NodeAPI:
server.models.Student.findOne({where: {RFID: id},fields: {id: true,schoolId: true,classId: true}}, function (err, data) {
if (err)
callback(err);
else {
callback();
}
})
Query for RestAPI :
$http.get('http://localhost:3000/api/services?filter[fields][id]=true&filter[fields][make]=true&filter[fields][model]=true')
.then(function (response) {
}, function (error) {
});
You can use fields projections,
Sample Record:
{ name: 'Something', title: 'mr', description: 'some desc', patient: { name: 'Asvf', age: 20, address: { street: 1 }}}
First Level Projection:
model.find({ fields: { name: 1, description: 1, title: 0 } })
and I think Strong loop is not yet supporting for second-level object filter, does anyone know how to filter second-level object properties or is yet to implement?.
Second Level Projection: (Need help here)
Ex: 2
model.find({ fields: { name: 1, 'patient.name': 1, 'patient.age': 1, 'patient.address': 0 } })
// Which results { name } only