elasticsearch run multiple different query in one call - angularjs

I want to run 3 differents query (on the same index) with one call on elasticsearch service.
Is this possible ?
More elaborate question :
I make an autocomplete function in angularjs who search on 3 fields and display them :
"T_FAMILY" + "T_GENUS" + "T_SCIENTIFICNAME".
i was making only one query :
"query" : { "query_string" : { "query" : "T_FAMILY:" +value +" or T_GENUS:"+value+ " or T_SCIENTIFICNAME:"+value} }
// value is the user input and can contain wildcard *
but not revelant results.
Now i want to make 3 different query and sort each one by score. and finally get the 3 results and
merge them in an array and sort by score (i do this by my addKeyword() function).
var keywords = [];
keywords.push(val);
$scope.isHide.logo=true;
return elasticQuery.search({
index: $scope.domaine,
size: 20,
_source: false,
body: {
"fields" : ["T_FAMILY","T_GENUS","T_SCIENTIFICNAME"],
"query": { "bool" : {"must" : [{"wildcard" : { "T_FAMILY" : val }}]}},
"sort" : { "_score" : "desc" }
}
}).then(function (response){
addKeyword(response,keywords);
return elasticQuery.search({
index: $scope.domaine,
size: 20,
_source: false,
body: {
"fields" : ["T_FAMILY","T_GENUS","T_SCIENTIFICNAME"],
"query": {"bool" : {"must" : [{"wildcard" : { "T_GENUS" : val }}]}},
"sort" : { "_score" : "desc" }
}
}).then(function (response) {
addKeyword(response,keywords);
return elasticQuery.search({
index: $scope.domaine,
size: 20,
_source: false,
body: {
"fields" : ["T_FAMILY","T_GENUS","T_SCIENTIFICNAME"],
"query": {"bool" : {"must" : [{"wildcard" : { "T_SCIENTIFICNAME" : val }}]}},
"sort" : { "_score" : "desc" }
}
}).then(function (response) {
addKeyword(response,keywords);
return keywords;
});
return keywords;
});
});
I didn't find anything who help so i make 3 imbricated call of elastichsearch in my js code but it's not the best way maybe.
Thanks

it is possible to run differents queries in elasticsearch with "dis_max" :
return elasticQuery.search({
index: $scope.domaine,
size: 20,
_source: false,
body: {
//"min_score" : 0.50,
"fields" : ["T_FAMILY","T_GENUS","T_SCIENTIFICNAME"],
"highlight": {"pre_tags": ["<strong>"], "post_tags": ["</strong>"], "fields": { "T_FAMILY": {},"T_GENUS" : {}, "T_SCIENTIFICNAME": {} }},
"query" : {
"dis_max" : {
"tie_breaker" : 0.0,
"boost" : 1.0,
"queries" : [
{"wildcard" : { "T_FAMILY" : val }},
{"wildcard" : { "T_GENUS" : val }},
{"wildcard" : { "T_SCIENTIFICNAME" : val }}
]
}
},
"sort" : { "_score" : "desc" }
}
}).then(function (response){
return addKeywords(response,keywords);
});

Related

Update documents nested multiple levels in an array

I have this JSON structure in MongoDb and want to update changing a specific value of a particular item in a nested array. I would like to change the key targetAreaId from USER_MESSAGE to VISUAL_MESSAGE.
{
"_id" : "5cde9f482f2d5b924f492da2",
"scenario" : "SCENARIOX",
"mediaType" : "VISUAL",
"opCon" : "NORMAL",
"stepConfigs" : [
{
"stepType" : "STEPX",
"enabled" : true,
"configs" : [
{
"contentTemplateId" : "5cde9f472f2d5b924f492973",
"scope" : "STANDARD",
"key" : "CONTENT"
},
{
"priorityId" : "5cde9f472f2d5b924f49224f",
"scope" : "STANDARD",
"key" : "PRIORITY"
},
{
"targetAreaId" : "USER_MESSAGE",
"scope" : "STANDARD",
"key" : "TARGET_AREA"
}
],
"description" : "XPTO"
}
],
"scope" : "STANDARD" }
How can I do it in the same time?
EDIT
I am trying this way:
var cursor = db.getCollection('CollectionX').find({
"scenario": "SCENARIOX",
"stepConfigs.stepType": "STEPX",
"stepConfigs.configs.key": "TARGET_AREA"
});
if (cursor.hasNext()) {
var doc = cursor.next();
doc.stepConfigs.find(function(v,i) {
if (v.stepType == "STEPX") {
doc.stepConfigs[i].configs.find(function(w,j) {
if (w.key == "TARGET_AREA") {
var result = db.getCollection('CollectionX').update(
{ "_id" : doc._id },
{ "$set" : { doc.stepConfigs[i].configs[j].targetAreaId: "VISUAL_MESSAGE" }}
);
}
});
};
});
} else {
print("Step does not exist");
}
But the error below is occurring:
Error: Line 15: Unexpected token .
I don't think that's possible.
You can update the specific element you want using this query:
db.test_array.updateOne({}, {
$set: {
"stepConfigs.$[firstArray].configs.$[secondArray].targetAreaId": "VISUAL_MESSAGE"
}
}, {
arrayFilters: [{
"firstArray.stepType": "STEPX"
}, {
"secondArray.targetAreaId": "USER_MESSAGE"
}]
})
But pushing in the same array at the same time does render this (this was for the original model, but it's still the same problem, you can't $set and $push in the same array this way):
> db.test_array.updateOne({"step.type":"B"},{$push:{"step.$.configs":{"className":"something"}}, $set:{"step.$.configs.$[secondArray].targetAreaId":"TA-1"}},{arrayFilters:[{"secondArray.targetAreaId":"TA-2"}]})
2019-09-06T13:53:44.783+0200 E QUERY [js] WriteError: Updating the path 'step.$.configs.$[secondArray].targetAreaId' would create a conflict at 'step.$.configs' :

Query on array of array object in mongodb

Following is my product collection in mongodb..
{
"_id" : ObjectId("56d42389db70393cd9f47c22"),
"sku" : "KNITCHURI-BLACK",
"options" : [
{
"sku" : "KNITCHURI-BLACK-M",
"stores" : [
{
"code" : "6",
"quantity" : 0
},
{
"code" : "10",
"quantity" : 26
}
],
"ean_code" : "2709502",
"size" : "M"
},
{
"sku" : "KNITCHURI-BLACK-S"
"stores" : [
{
"code" : "6",
"quantity" : 0
},
{
"code" : "10",
"quantity" : 30
}
],
"size" : "S"
}
]
}
want query on where { 'options.stores.code' : '6' } and { 'options.stores.quantity' : { $gt : 0 } }, How i query on this collection then i got response? Kindly help on this issue..
Here is the two approaches to get documents in Mongoose.
You can change the Mongo query if required as given in the various answers. I have just used your approach for Mongo query.
Approach 1 - Using cursor - Recommended Approach
Approach 2 - Using Query
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Schema = mongoose.Schema, ObjectId = Schema.ObjectId;
var Store = new Schema({
code : String,
quantity : Number
});
var Option = new Schema({
sku : String,
stores : [ Store ],
ean_code : String,
size : String
});
var productSchema = new Schema({
_id : ObjectId,
sku : String,
options : [ Option ]
});
var Product = mongoose.model('product', productSchema, 'product');
console.log("Cursor Approach #1");
var cursor = Product.find({
'options.stores' : {
$elemMatch : {
code : '6',
quantity : {
$gt : 0
}
}
}
}).cursor();
console.log("Curosr Results***************************************");
cursor.on('data', function(doc) {
console.log("Getting doc using cursor ==========>" + JSON.stringify(doc));
});
cursor.on('close', function() {
console.log("close the cursor");
});
console.log("Query Approach #2");
var query = Product.find({
'options.stores' : {
$elemMatch : {
code : '6',
quantity : {
$gt : 0
}
}
}
});
console.log("Query Results***************************************");
query.exec(function(err, doc) {
if (err) {
console.log(err);
}
console.log("Getting doc using query ==========>" + JSON.stringify(doc));
});
I think you need to unwind options
db.product.aggregate( [
{ $unwind: "$options" }
{ $match: { 'options.stores.code' : '6','options.stores.quantity' : { $gt : 0 }}
] )
As far as I understand the question, you want to find a products that are in stock in stores with code 6. The following query does that:
db.collection.find({"options.stores" : {$elemMatch: {"code" : "6", "quantity" : {$gt : 0}}}});

update nested array element value in node js mongoDB [duplicate]

This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 6 years ago.
Hi i am new in nodejs i need to update a value in nested array using _id of document my database document is look like this..
"complaints" : [
{
"complaint" : "head light is not working",
"complaintid" : ObjectId("57205219a56d2b8c0f9274a4"),
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"labour" : 350,
"partCost" : 0,
"part" : [
{
"id" : ObjectId("56f12eaab915bd9800272ed7"),
"estimate" : 450,
"partname" : "clutch",
"_id" : ObjectId("57454cef49218eb40c1c0d25"),
"quantity" : 0,
"qrcodes" : []
},
{
"id" : ObjectId("56f12eaab915bd9800272ed7"),
"estimate" : 450,
"partname" : "rear tyre",
"_id" : ObjectId("57454cef49218eb40c1c0d24"),
"quantity" : 0,
"qrcodes" : []
}
],
"acceptance" : true,
"inspection" : false,
"color" : "#8929A9",
"status" : "APPROVED",
"estimate" : 1200,
"solution" : "HEAD LIGHT CHANGE",
"problems" : "HEAD LIGHT IS NOT WORKING"
},
i need to update quantity value of part array exist inside the part array using _id of part array
i am trying this but its not working what should i do for update this value...
var partdata = req.payload.parts;
for(var k = 0; k< partdata.length ; k++ ){
CPS.update({
'complaints.part._id' : partdata[k].partid
}, {
"$inc" : {
'complaints.part.$.quantity' : partdata[k].quantity
}
}).exec
(function(err,temp) {
if(err){
res(err).code(500);
}else{
console.log(temp);
}
});
}
MongoDB doesn't support matching into more than one level of an array.
Consider altering your document model so each document represents an
operation, with information common to a set of operations duplicated
in the operation documents.
Following is not the solution for your case.
But in-case you know the index then you could do something like this:
Assume a sample document like:
{
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"part" : [{ "quantity" : 111 }, { "quantity" : 222 }]
}
Then this query should work.
db.test.update({ "_id" : ObjectId("57454c9249218eb40c1c0d1f") }, { "$set" : { "part.1.quantity" : 999 } })
Document will get modified as follows :
{
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"array" : [{ "quantity" : 222 }, { "quantity" : 999 }]
}
Update: You can try following way of doing the update. But its not recommended way of doing probably you need to restructure your schema.
db.test.aggregate([
{ "$unwind": "$complaints" },
{ "$unwind": "$complaints.part" },
{ "$project":
{
_id: "$complaints.part._id",
partqty: "$complaints.part.quantity"
}
},
]);
This should return as follows:
{
"_id" : ObjectId("57454cef49218eb40c1c0d25"),
"partqty" : 111
}
{
"_id" : ObjectId("57454cef49218eb40c1c0d24"),
"partqty" : 222
}
Now you can use this information to update, e.g
var cur = db.test.aggregate([
{ "$unwind": "$complaints" },
{ "$unwind": "$complaints.part" },
{ "$project":
{
_id: "$complaints.part._id",
partqty: "$complaints.part.quantity"
}
},
]);
while (cur.hasNext()) {
var doc = cur.next();
//Note the index should be know again :|
db.test.update({ "complaints.part._id": ObjectId("57454cef49218eb40c1c0d25") },
{ "$set": { "complaints.$.part.1.quantity": 55 }},
{ "multi": true})
}

angularjs and elasticsearch js api, how to force GET instead of POST

I use elasticsearch javascript api with angularjs. This is working very good but i need to query the elasticsearch service through a middleware to filter dangerous request ( delete , update ). the middleware work with 'GET' but the API use by default 'POST' query.
According to the doc i can specify a parameter 'method' to use 'GET' query by the API :
API Conventions
It work with 'POST' but failed with 'GET',"GET' and i have an error :
Error: elasticQuery.search(...) is undefined
How can i do ? 'Get' can work with long and complexe query like this example bellow ?
this is how i try it :
return elasticQuery.search({
method : 'GET',
index: 'indexbotanic',
from: 0
size: 10,
body: {
"fields" : ["C_COLLECTIONCODE", "T_SCIENTIFICNAME", "T_SCIENTIFICNAMEAUTHORSHIP", "T_SPECIFICEPITHET", "T_KINGDOM", "T_PHYLUM", "T_CLASS_", "T_ORDER_", "T_FAMILY", "T_GENUS", "T_SUBGENUS", "T_VERNACULARNAME", "O_CATALOGNUMBER", "O_RECORDNUMBER", "O_CREATED", "O_SEX", "I_INSTITUTIONCODE", "D_DETERMINATIONID", "D_IDENTIFIEDBY", "M_IDENTIFIER", "E_RECORDNUMBER", "E_RECORDEDBY", "L_CONTINENT", "L_COUNTRY", "L_COUNTRYCODE", "L_COUNTY", "L_LOCALITY"],
"query" : {
"filtered" : {
"filter" : {
"and" : [{
"or" : [{
"term" : {
"L_CONTINENT" : "europe"
}
}
]
}, {
"or" : [{
"term" : {
"T_FAMILY" : "lamiaceae"
}
}
]
}, {
"or" : [{
"term" : {
"E_RECORDEDBY" : "balay, r."
}
}, {
"term" : {
"E_RECORDEDBY" : "boissier, p.e."
}
}
]
}, {
"or" : [{
"term" : {
"T_SCIENTIFICNAME" : "lamium amplexicaule"
}
}
]
}, {
"or" : [{
"term" : {
"T_GENUS" : "lamium"
}
}, {
"term" : {
"T_GENUS" : "betonica"
}
}
]
}
]
}
}
},
"highlight" : {
"pre_tags" : ["<strong>"],
"post_tags" : ["</strong>"],
"fields" : {
"C_COLLECTIONCODE" : {},
"O_CATALOGNUMBER" : {},
"O_RECORDNUMBER" : {},
"O_CREATED" : {},
"O_SEX" : {},
"D_DETERMINATIONID" : {},
"D_IDENTIFIEDBY" : {},
"E_EVENTID" : {},
"E_RECORDNUMBER" : {},
"E_RECORDEDBY" : {},
"L_CONTINENT" : {},
"L_COUNTRY" : {},
"L_COUNTRYCODE" : {},
"L_COUNTY" : {},
"L_LOCALITY" : {},
"T_SCIENTIFICNAME" : {},
"T_SCIENTIFICNAMEAUTHORSHIP" : {},
"T_SPECIFICEPITHET" : {},
"T_KINGDOM" : {},
"T_PHYLUM" : {},
"T_CLASS_" : {},
"T_ORDER_" : {},
"T_FAMILY" : {},
"T_GENUS" : {},
"T_SUBGENUS" : {},
"T_VERNACULARNAME" : {}
}
},
"aggs" : {
"L_CONTINENT_MISSING" : {
"missing" : {
"field" : "L_CONTINENT"
}
},
"O_SEX_MISSING" : {
"missing" : {
"field" : "O_SEX"
}
},
"I_INSTITUTIONCODE_MISSING" : {
"missing" : {
"field" : "I_INSTITUTIONCODE"
}
},
"T_TAXONRANK_MISSING" : {
"missing" : {
"field" : "T_TAXONRANK"
}
},
"D_TYPESTATUS_MISSING" : {
"missing" : {
"field" : "D_TYPESTATUS"
}
},
"O_HASMEDIA_MISSING" : {
"missing" : {
"field" : "O_HASMEDIA"
}
},
"T_SCIENTIFICNAME_MISSING" : {
"missing" : {
"field" : "T_SCIENTIFICNAME"
}
},
"T_FAMILY_MISSING" : {
"missing" : {
"field" : "T_FAMILY"
}
},
"T_GENUS_MISSING" : {
"missing" : {
"field" : "T_GENUS"
}
},
"E_RECORDEDBY_MISSING" : {
"missing" : {
"field" : "E_RECORDEDBY"
}
},
"L_CONTINENT" : {
"terms" : {
"field" : "L_CONTINENT",
"size" : 20
}
},
"O_SEX" : {
"terms" : {
"field" : "O_SEX",
"size" : 20
}
},
"I_INSTITUTIONCODE" : {
"terms" : {
"field" : "I_INSTITUTIONCODE",
"size" : 20
}
},
"T_TAXONRANK" : {
"terms" : {
"field" : "T_TAXONRANK",
"size" : 20
}
},
"D_TYPESTATUS" : {
"terms" : {
"field" : "D_TYPESTATUS",
"size" : 20
}
},
"O_HASMEDIA" : {
"terms" : {
"field" : "O_HASMEDIA",
"size" : 20
}
},
"T_SCIENTIFICNAME" : {
"terms" : {
"field" : "T_SCIENTIFICNAME",
"size" : 20
}
},
"T_FAMILY" : {
"terms" : {
"field" : "T_FAMILY",
"size" : 20
}
},
"T_GENUS" : {
"terms" : {
"field" : "T_GENUS",
"size" : 20
}
},
"E_RECORDEDBY" : {
"terms" : {
"field" : "E_RECORDEDBY",
"size" : 20
}
}
},
"sort" : "_score"
}
}).then(function (response) {
...
}
for example this work with GET :
curl -XGET 'http://localhost:9200/index/tablename/_search?pretty' -d '{
"query": {
"query_string": {
"query":"*keysearch*",
"fields": ["field1","field2","field3"]
}
}
}'
So how to force the api to send get with "-d '{ .... }' " ?
thanks a lot
Try to use this client: https://github.com/YousefED/elasticsearch.angular.simple and change POST into GET. I'm not sure which browsers support GET requests with a body though, you might be running into a limitation there.

MongoDB find the intersection of arrays

docs:
order1.filter = ['tag1','tag2']
order2.filter = ['tag1','tag2','tag3']
want to get:
query ['tag1','tag2'] -> (only order1)
query ['tag1','tag2','tag3'] -> (order1 and order2)
query ['tag1','tag2','tag3','tag4', etc ] -> (order1 and order2)
and
query ['tag1','tag3'] -> (null)
query ['tag2','tag3'] -> (null)
All values ​​order.filter should be necessarily in the query array
How to do it? Tried directives $all, $in :(
You can do this with aggregation framework (there is no way to do this with regular find that I know of).
I think this is basically a duplicate so adjusting that code for your fields you get something like:
//sample documents:
> db.docs.find({},{_id:0})
{ "order" : 1, "filter" : [ "t1", "t2" ] }
{ "order" : 2, "filter" : [ "t1", "t2", "t3" ] }
var tagArray = [ "t1", "t2" ]; // array to "match"
db.docs.aggregate( [
{
"$project" : {
"order" : 1,
"filter" : 1,
"killFlag" : {
"$const" : [
true,
false
]
}
}
},
{
"$unwind" : "$filter"
},
{
"$unwind" : "$killFlag"
},
{
"$match" : {
"$nor" : [
{
"filter" : {
"$in" : tagArray
},
"killFlag" : true
}
]
}
},
{
"$group" : {
"_id" : "$order",
"filter" : {
"$addToSet" : "$filter"
},
"killFlag" : {
"$max" : "$killFlag"
}
}
},
{
"$match" : {
"killFlag" : false
}
},
{
"$project" : {
"_id" : 1,
"filter" : 1
}
}
]);

Resources