Penalizing documents in facet results based on their content - search

If we have the following documents in elasticsearch:
[
{'name': 'John', 'time': '2013-01-01 12:01:00'},
{'name': 'John', 'time': '2013-01-01 12:02:00'},
{'name': 'John', 'time': '2013-01-01 12:03:00'},
{'name': 'John', 'time': '2013-01-01 12:04:00'},
{'name': 'Harry', 'time': '2013-01-01 12:05:00'},
{'name': 'Fred', 'time': '2013-01-01 12:06:00'},
{'name': 'Fred', 'time': '2013-01-01 12:07:00'}
]
And we facet over the 'name' field, we'll get something like this:
"facets": {
"count_per_name": {
"_type": "terms",
"missing": 0,
"total": 7,
"other": 0,
"terms": [
{
"term": "John",
"count": 4
},
{
"term": "Fred",
"count": 2
},
{
"term": "Harry",
"count": 1
}
]
}
}
My question is this: is it possible to perform a faceting query in elasticsearch whereby those documents with the name "John" count as "half" documents? This would lead to John's count falling from 4 to 2, but Fred's and Harry's remaining the same:
"facets": {
"count_per_name": {
"_type": "terms",
"missing": 0,
"total": 5,
"other": 0,
"terms": [
{
"term": "John",
"count": 2
},
{
"term": "Fred",
"count": 2
},
{
"term": "Harry",
"count": 1
}
]
}
}

you could play with http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html
and specify value_script, where return 0.5 for John and 1 for other guys, and operate with SUM facet result. Though this approach is performance affected

Related

How to print the first true and first false in python

I have a set with time and each row either has a value of true or false and I want to print out the first row of true, then skip until it becomes false and print that alternating between those through the whole file
this is just an example of the set that I have the true values represent if the speed and distance to an object is less than a given number
What I want it to print
any ideas on how to do this in python
I've taken your data and converted it in to a list of Python dict structures. You could easily use a list of lists ([ [..], [..], ... ]) but a dict makes it easier to imagine when starting out
data = [
{'id': 1, "time": "10/03/2022 01:20", "bool": True},
{'id': 2, "time": "10/03/2022 01:20", "bool": True},
{'id': 3, "time": "10/03/2022 01:20", "bool": True},
{'id': 4, "time": "10/03/2022 01:20", "bool": False},
{'id': 5, "time": "10/03/2022 01:20", "bool": False},
{'id': 6, "time": "10/03/2022 01:20", "bool": False},
{'id': 7, "time": "10/03/2022 15:13", "bool": True},
{'id': 8, "time": "10/03/2022 15:13", "bool": True},
{'id': 9, "time": "10/03/2022 15:13", "bool": False},
{'id': 10, "time": "10/03/2022 15:13", "bool": True}
]
current_bool=None
for row in data:
if current_bool != row['bool']:
print(row)
current_bool=row['bool']
The output is:
{'id': 1, 'time': '10/03/2022 01:20', 'bool': True}
{'id': 4, 'time': '10/03/2022 01:20', 'bool': False}
{'id': 7, 'time': '10/03/2022 15:13', 'bool': True}
{'id': 9, 'time': '10/03/2022 15:13', 'bool': False}
{'id': 10, 'time': '10/03/2022 15:13', 'bool': True}

How to project an item in an array to the top level and also fetch only the matched objects in the array

Currently this is an example of a dataset in my salesOrder collection
{
"totalCost": 4,
"salesOrderRef": "s4",
"customerRef": "c10",
"date": "2021-06-03T00:00:00.000Z",
"etd": "2021-06-24T00:00:00.000Z",
"delivered": true,
"paid": false,
"inventory": [{
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
}, {
"sku": "i2",
"quantity": 2,
"priceEa": 2,
"discount": 2
}]
}
How do I get it to match
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
}
if I search sku: i3? If there are any duplicate sku in the inventory array of a single salesOrder document, I would also like it to duplicate another result out, like
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
},
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 3,
"priceEa": 4,
"discount": "0"
}
How could I achieve this? I tried using aggregation and filters but I'm not sure how
Try this aggregation query, from what I understood this is should give you the output document you have mentioned.
db.collection.aggregate([
{
$unwind: "$inventory"
}, {
$project: {
"_id" : 0,
"salesOrderRef": 1,
"customerRef": 1,
"sku": "$inventory.sku",
"quantity": "$inventory.quantity",
"priceEa": "$inventory.priceEa",
"discount": "$inventory.discount"
}
}, ])

Node JS How to build a nested object using parent ids

for my internship, I need to build a nested object using parent IDs I don't want children attribute array.
I have an array of object with id and parent id and I use npm flatnest to do it. This works for a one-level hierarchy but the code must be adapted for a multi-hierarchy level.
I don't know how to adapt that to multi-hierarchy level.
This is my array of Object
var fn = require("flatnest");
const flat =
[
{ "id": 1, "name": 'Restaurants', 'parentId': 0},
{ "id": 2, "name": 'family restaurant', 'parentId': 1, 'value':'Excellent'},
{ "id": 3, "name": 'Sun restaurant', 'parentId': 1,'value':""},
{ "id": 4, "name": 'Sun restaurant 1', 'parentId': 3, 'value':'Good'},
{ "id": 5, "name": 'Sun restaurant 2', 'parentId': 3, 'value':"bad"},
{ "id": 6, "name": 'Hotels', 'parentId': 0,'value':""},
{ "id": 7, "name": 'Space Hotel', 'parentId': 6,'value':""},
{ "id": 8, "name": 'Sun Hotel', 'parentId': 7,'value':'Nice'},
{ "id": 9, "name": 'Moon Hotel', 'parentId': 7,'value':""},
{ "id": 10, "name": 'Moon Hotel 1', 'parentId': 9, 'value':"Excellent"},
{ "id": 11, "name": 'Moon Hotel 2', 'parentId': 9, 'value':"Worst"},
];
To use nested function of npm flatnest, I have to flat my array of Object (const flat)
My code to flat :
var transform={};
for(var i=0;i<flat.length;i++)
{
if(typeof flat[parseInt(i)+1] !== 'undefined' )
{
if(flat[i].id==flat[i+1].parentId)
{
var t = flat[i].name;
transform[t.concat(".").concat(flat[i+1].name)]=flat[i+1].value;
}else{
transform[t.concat(".").concat(flat[i+1].name)]=flat[i+1].value;
}
}
}
console.log(transform)
var nested = fn.nest(transform)
console.log(nested)
I expect the output of console.log(transform) to be
{ 'Restaurants.family restaurant':'Excellent',
'Restaurants.Sun restaurant.Sun restaurant 1': 'Good',
'Restaurants.Sun restaurant.Sun restaurant 2': 'bad',
'Hotels.Space Hotel.Sun Hotel': 'Nice',
'Hotels.Space Hotel.Moon Hotel.Moon Hotel 1': 'Excellent',
'Hotels.Space Hotel.Moon Hotel.Moon Hotel 2' : 'Worst'}
Then by using nested function :
var nested = fn.nest(transform)
console.log(nested)
The output must be exactly like that :
"Restaurants":{
"family restaurant":"Excellent",
"Sun restaurant":{
"Sun restaurant 1":"Good",
"Sun restaurant 2":"bad"
}
},
"Hotels":{
"Space Hotel":{
"Sun Hotel":"Nice",
"Moon Hotel":{
"Moon Hotel 1":"Excellent",
"Moon Hotel 2":"Worst"
}
}
}
}
but the actual output of console.log(transform) is :
{'Restaurants.family restaurant':'Excellent',
'Restaurant.Sun restaurant':'',
'Sun restaurant.Sun restaurant 1':'Good',
'Sun restaurant.Sun restaurant 2':'bad',
'Sun restaurant.Hotels':'',
'Hotels.Space Hotel':'',
'Space Hotel.Sun Hotel':'Nice'
'Space Hotel.Moon Hotel':'',
'Moon Hotel.Moon Hotel 1':'Excellent',
'Moon Hotel.Moon Hotel 2': 'Worst'}
I'm not using flatnest. But the below code works for me. Please check and let me know if it doesn't work for any scenario.
const flat = [{
"id": 1,
"name": 'Restaurants',
'parentId': 0
},
{
"id": 2,
"name": 'family restaurant',
'parentId': 1,
'value': 'Excellent'
},
{
"id": 3,
"name": 'Sun restaurant',
'parentId': 1,
'value': ""
},
{
"id": 4,
"name": 'Sun restaurant 1',
'parentId': 3,
'value': 'Good'
},
{
"id": 5,
"name": 'Sun restaurant 2',
'parentId': 3,
'value': "bad"
},
{
"id": 6,
"name": 'Hotels',
'parentId': 0,
'value': ""
},
{
"id": 7,
"name": 'Space Hotel',
'parentId': 6,
'value': ""
},
{
"id": 8,
"name": 'Sun Hotel',
'parentId': 7,
'value': 'Nice'
},
{
"id": 9,
"name": 'Moon Hotel',
'parentId': 7,
'value': ""
},
{
"id": 10,
"name": 'Moon Hotel 1',
'parentId': 9,
'value': "Excellent"
},
{
"id": 11,
"name": 'Moon Hotel 2',
'parentId': 9,
'value': "Worst"
},
];
const map = new Map();
const result = flat.reduce((acc, curr) => {
let val = {}
if (curr.parentId == 0)
acc[curr.name] = val;
else {
if (map.get(curr.parentId)) {
if (curr.value != '')
val = curr.value;
map.get(curr.parentId)[curr.name] = val;
}
}
map.set(curr.id, val);
return acc;
}, {});
console.log(JSON.stringify(result));

Mongoose, mongodb, bad aggregate grouping

I m actually trying to get some information concerning my app.
I have to get some informatiogrouping by day / month / year. I have the good result attributes, but information is displayed even if there is nothing in DB.
NB : Start and End are good formatted dates.
TraitementNettoyage.aggregate([
{$match: { 'dateEntre': {$gt: start}, 'dateEntre': {$lt: end} }},
{$group: {'_id': {'day': {'$dayOfMonth': '$dateEntre'}, 'month': {'$month': '$dateEntre'}, 'year': {'$year': '$dateEntre'}}, count: {$sum: 1}}}
]).exec((err, res)=>
console.log res
)
And I get this resultset :
[
{
"_id": {
"day": 24,
"month": 3,
"year": 2015
},
"count": 2
}
]
The fact is that I have nothing in DB concerning the 2015-03-24.
In my DB, I have only 2 sets of data with the 2015-03-23 date.
What should I correct in my request to get the exact two resultsets :
[
{
"_id": {
"day": 24,
"month": 3,
"year": 2015
},
"count": 0
}
]
and
[
{
"_id": {
"day": 23,
"month": 3,
"year": 2015
},
"count": 2
}
]
?
EDIT :
Here the resultset with $lte and $gte :
[
{
"_id": {
"day": 25,
"month": 3,
"year": 2015
},
"count": 2
},
{
"_id": {
"day": 24,
"month": 3,
"year": 2015
},
"count": 2
}
]
The problem is that the count are not correct. in fact it should be 2 for 24/03/2015 and 0 for 25/03/2015.
Thanks for advance
split the $match for dateEntre
TraitementNettoyage.aggregate([
{$match: { 'dateEntre': {$gte: start}}},
{$match: { 'dateEntre': {$lte: end}}},
{$group: {'_id': {'day': {'$dayOfMonth': '$dateEntre'}, 'month': {'$month': '$dateEntre'}, 'year': {'$year': '$dateEntre'}}, count: {$sum: 1}}}
]).exec((err, res)=>
console.log res
)

Querying with mongoose/mongoDB on nested document

I have a car model given as below
{
"_id": "54b8a71843286774060b8bed",
"name": "Car1",
"active": true,
"model": [
{
"name": "Model1",
"active": true,
"_id": "54b8a71843286774060b8bee",
"available": [
{
"Day": "Mon",
"quantity": "6"
},
{
"Day": "Tue",
"quantity": "6"
},
{
"Day": "Wed",
"quantity": "6"
},
{
"Day": "Thurs",
"quantity": "6"
},
{
"Day": "Fri",
"quantity": "0"
}
]
},
{
"name": "Model2",
"active": true,
"_id": "54b8a71843286774060b8bef",
"available": [
{
"Day": "Mon",
"quantity": "6"
},
{
"Day": "Tue",
"quantity": "6"
},
{
"Day": "Wed",
"quantity": "6"
},
{
"Day": "Thurs",
"quantity": "6"
},
{
"Day": "Fri",
"quantity": "6"
}
]
},
{
"name": "Model3",
"active": true,
"_id": "54b8a71843286774060b8beg",
"available": [
{
"Day": "Mon",
"quantity": "6"
},
{
"Day": "Tue",
"quantity": "6"
},
{
"Day": "Wed",
"quantity": "6"
},
{
"Day": "Thurs",
"quantity": "6"
},
{
"Day": "Fri",
"quantity": "0"
}
]
}
]
}
I am trying to search availability of car on given days.
Like if I select Friday then it should return me cars whose quantity more than 0 on Friday but currently it is returning all the cars having quantity 0 as well.
I have written query as below
Car.find({
'active': true,
'model.available': {
$elemMatch: {
quantity: {$gte : 1}
}
}
})
But it returning documents those are having quantity 0 also.
For this, you'll need the aggregation pipeline.
The following code snippet does this:
Find all documents with at least one matching model.
Split up the documents: a document with an array of 3 models in it gets turned into three documents with one model each:
{name: "Car1": 1, models: [{name: "Model1"}, {name: "Model2"}, {name: "Model3"}]}
Becomes:
{name: "Car1", models: {name: "Model1"}} & {name: "Car1", models: {name: "Model2"}} & {name: "Car1", models: {name: "Model3"}}.
The split up documents are filtered (again) on quantity and day.
Optionally, glue the documents back together again. You might not need that in your application.
db.cars.aggregate([
// First, we do your query, which will return
// every document that has _at least one_
// model that is available.
{$match: {
'active': true,
'model.available': {$elemMatch: {
'quantity': {$gte: 1},
'Day': 'Fri'
}}
}},
// We split up the found documents,
// every document will now have exactly
// one 'model' in it.
{$unwind: "$model"},
// We now filter the split documents.
{$match: {
'model.available': {$elemMatch: {
'quantity': {$gte: 1},
'Day': 'Fri'
}}
}},
// If you want, you can now glue the
// models back together again.
{$group: {
_id: "$_id", // Group all documents with the same _id
name: {$first: "$name"},
active: {$first: "$active"},
model: {$push: "$model"} // Make an array of models
}}
])
Important note: For $gte to work, you'll need to store your quantity as a Number, not a String. Since your example has the numbers stored as strings, you might want to double check them in your database.

Resources