Match range for value with MongoDB - node.js

I have a campaign collection, which is for advertisers. It's schema is:
var campaignSchema = new mongoose.Schema({
name: String,
sponsor: String,
[...]
target: {
age: {
lower: Number,
upper: Number
},
gender: String,
locations: Array, // [ { radius: '', lon: '', lat: '' } ]
activities: Array
}
});
I need to run a query with a specific age, and return all campaigns where that age is between age.lower and age.higher.
I have read the docs for $gt and $lt, however they appear to only work one way (so I could specify a range and match a value, however I need to specify a value and match a range).
Any suggestions?

Sorry I misunderstood the problem, I got it now.
db.collection.find( { "age.lower": { $lt: value1 }, "age.upper": { $gt: value1 } } );
So, for example, if your range is 25 to 40, and value1 is 30, 25 < 30 and 40 > 30 -- match!
If you use the same range with 20, 25 !< 20 -- will not match.

You could first create a query on the lower bound of that value, sort the results in descending order and get the top document from the result. Compare that document with the upper bound, if there is a match then that document has a range which contains that age. For example:
var age = 23;
var ads = db.campaign.find({ "age.lower": {"$lte": age } }).sort({"age.lower": -1}).limit(1);
if (ads != null) {
var result = ads[0];
if (result.age.upper > age) {
return result;
} else {
return null;
}
}

Related

using for loop with push() to create arrays within a new array

I'm working on a project where I need to declare customsItem formatted in a particular way.
The format given is:
var customsItem = {
"description":"T-Shirt",
"quantity":20,
"net_weight":"1",
"mass_unit":"lb",
"value_amount":"200",
"value_currency":"USD",
"origin_country":"US",
};
In my project however, I have multiple descriptions, so I need to make customsItem an array containing both.
I have array itemInCart =
[
{
itemDescription: 't-shirt',
qty: 1,
pre_orderQty: 1,
price: 30,
weight: 8
},
{
itemDescription: 'pants',
qty: 0,
pre_orderQty: 1,
price: 40,
weight: 5
}
]
I need to get these items in the correct format and within an array called customsItem. I thought to do this using a for loop with push(). Currently, I'm not getting anything when I try to console.log(customsItem), so I'm not sure if this is the best way to achieve the results that I am trying to get. I would really appreciate any help or advice on how to correctly get the results that I need. Thank you!
const customsItem = [];
for (var item of itemInCart) {
const items = {
"description":item.itemDescription,
"quantity":item.qty + item.pre_orderQty,
"net_weight":item.weight,
"mass_unit":"oz",
"value_amount":item.price,
"value_currency":"USD",
"origin_country":"US",
}
customItem.push(
items
)
}
You are not pushing into the correct array:
const customsItem = [];
for (var item of itemInCart) {
const items = {
"description":item.itemDescription,
"quantity":item.qty + item.pre_orderQty,
"net_weight":item.weight,
"mass_unit":"oz",
"value_amount":item.price,
"value_currency":"USD",
"origin_country":"US",
}
customItem.push( <---- needs to be customsItem.push
items
)
}

MongoDB - How to get the documents based on two column values

My MongoDB collection with sample data is attached with the screenshot below
I want to fetch rows by passing grade value and the resulting records should be returned as follows
case 1: when grade = 12, Row 1,3,6 and 7 should be returned ie given
grade 12 should compare with gradeFrom and gradeTo
case 2: when grade = 1, Row 5 should returned
As a summary of above cases, the given grade should be greater than or equal to gradeFrom AND less than or equal to gradeTo.
The mongoose query that I used is given below, but the data returned is empty in my code
let andCondition = [];
let grade = 12;
andCondition.push({ gradeFrom: {$gte: grade}});
andCondition.push({ gradeTo: {$lte: grade}});
let data = await Course.find({$and :andCondition});
console.log(andCondition) gives the below object
[
{ gradeFrom: { '$gte': 12 } },
{ gradeTo: { '$lte': 12 } }
]
Please help me to get this done.
You have reversed the range logic.
In Math, it should be:
gradeFrom <= grade <= gradeTo
While in MongoDB query:
{ gradeFrom: { $lte: grade } }
{ gradeTo: { $gte: grade } }

mongodb - most efficient way of calculating missing indices in sequence

Given a collection with lets say 1.000.000 entries and each of them have their own unique property called number which is indexed. How can I efficiently find the lowest gap in the number sequence.
An easy example would be a sequence of indexes like: 1,2,3,4,6,7,10, where I would like to get back the number 5 since this will be the lowest missing number in the sequence.
Is there a possible way (maybe aggregation) without the need to query all numbers.
One way of doing this would be with a cursor. With a cursor, you can manually iterate through the documents until you find one that matches your criteria.
var cursor = db.coll.find({}).sort({number: 1});
var prev = null
while (cusor.hasNext()) {
var curr = cursor.getNext()
if (prev && prev.number + 1 !== curr.number) break;
prev = curr;
}
One is get all the numbers and find the ones missing between them.
An aggregate example that you can use to not have to get them all. https://www.mongodb.com/community/forums/t/query-to-find-missing-sequence/123771/2
// Assuming the sample data with sequence numbers from 1 thru 10 as follows:
{ id: 1 },
{ id: 2 },
{ id: 4 },
{ id: 7 },
{ id: 9 },
{ id: 10 }
// And, note the missing numbers are 3, 5, 6 and 8. You can use the following aggregation to find them:
db.collection.aggregate([
{
$group: {
_id: null,
nos: { $push: "$id" }
}
},
{
$addFields: {
missing: { $setDifference: [ { $range: [ 1, 11 ] }, "$nos" ] }
}
}
])

Get field value from Array based on another field data matching

Below is my sample JSON object. I want to get the 'title' value based
on the longitude value. I have multiple(20-30) longitudes to get the titles, so I don't want to loop through those many times:
{
items:[
{
longitude:-72.897668,
latitude:40.453576,
title:52 street
},
{
longitude:-71.897668,
latitude:41.453576,
title:5th Ave
}
]
}
Can anyone suggest me how to get value without using for-loops.
Did you try something linke array.filter()?
function filterByLongitude(element) {
var expected = -72.897668
return element.longitude === expected;
}
var items = [{
longitude:-72.897668,
latitude:40.453576,
title:'52 street'
}, {
longitude:-71.897668,
latitude:41.453576,
title: '5th Ave'
}];
var match = items.filter(filterByLongitude);
console.log(match[0].title); // 52 street

Reading value of a key in an object using typescript

I have a array of objects and each object has two properties:
{key:count}
I am going to configure my chart and I should set the data source of the chart like below:
{meta: "unknown", value: [the count of unknown]},
{meta: "male", value: [the count of male]},
{meta: "female", value: [the count of female]}
Lets say my current array of objects is like:
[{"0":"10"}, {"1":"7"}, {"2":"9"}] in which 0 stands for unknown gender, 1 for male and 2 for female.
How can I set the value in the chart data in one line in such a way that it can find the count of each gender based on its key automatically from the array of objects.
Edit:
I have already written a method and it does the job:
public getKeyValue(data, key) {
for (var i = 0; i < data.length; i++) {
if (data[i].key == key)
return data[i].count;
}
return 0;
}
However, I was wondering if there's a single line code solution like LINQ.
You can, but it's not pretty.
This will do the job:
data.map(item => item.key === key ? item.count : 0).reduce((previous, current) => previous + current);
(Check an example in playground)
But I wouldn't recommend using this instead of your code, because your code won't iterate over all the array elements if one was found to match the criteria, with my solution regardless of whether or not the criteria was met, there will be two iterations over all the array elements.
For example:
var key = "key3",
data: { key: string, count: number}[] = [
{ key: "key1", count: 1 },
{ key: "key2", count: 2 },
{ key: "key3", count: 3 },
{ key: "key4", count: 4 },
{ key: "key5", count: 5 },
//...
{ key: "key1554", count: 1554 }
];
The array (data) has the length of 1554, but you're looking for the 3rd element.
Your way will have 3 iterations and then return the value, my way will have 3108 iterations, one cycle (1554) for the map function and then another cycle for the reduce function.

Resources