How can i optimize below query in Mongoose? - javascript

Basically, I want to fetch data from collection where pincode field(inside Location array) is matched by req.body
I'm getting my desired output but I'm not sure if it's a optimized way or not (look in Mongoose query part)
Here's my Json:
{
"_id" : ObjectId("6115b2cc1681596a10072f97"),
"vendorStatus" : "Active",
"name" : "harshit singh bhutani",
"email" : "sharsh2106#gmail.com",
"vId" : 12121,
"contact" : 121212,
"cities" : "dell",
"isMidnight" : "NA",
"location" : [
{
"delivery" : 1266,
"dc" : "High",
"midnight" : "Active",
"isLive" : "NA",
"_id" : ObjectId("612433c27292d11154bc4d4d"),
"pincode" : 123100,
"city" : "dek"
},
{
"delivery" : 23,
"dc" : "High",
"midnight" : "Active",
"isLive" : "NA",
"_id" : ObjectId("612441473cb5766a2457d6db"),
"pincode" : 1212,
"city" : "dd"
}
],
"createdAt" : ISODate("2021-08-12T23:46:20.407Z"),
"updatedAt" : ISODate("2021-09-03T10:51:34.756Z"),
"__v" : 73
}
Here's my query in Mongoose:
const { pin } = req.body;
const vendor = await Vendor.find({ vendorStatus: "Active" });
const pincode = vendor.map((item) => {
return item.location.find((i) => {
if (i.pincode === Number(pin) && i.isLive === "Active") {
return i;
}
});
});
const pincodefound = pincode.filter(Boolean);
if (pincodefound.length === 0) {
res.status(404);
throw Error("Product is not Deliverable at this Pincode");
} else {
return res.json({
pincodefound,
});
}
First I use map to iterate then I used find to grab the matched pincode after that I'm getting array with output and null value so I use filter to get only pincode
though I get my desired output BUT still I'm not sure weather its a optimized approach or not.

If I understood correctly your JS code you want to get only the value into the location array which match the condition.
In this case is a better way to do everything in a query. You can use an aggregation pipeline.
This query:
First match by vendorStatus: "Active like your find query.
Then use $unwind to deconstruct the array and look in each value.
$match to find a value which pincode and isLive are desired values.
And last stage is $project to show only values you want, in this case, the location values.
const pincode = await Vendor.aggregate([
{
"$match": {
"vendorStatus": "Active"
}
},
{
"$unwind": "$location"
},
{
"$match": {
"location.pincode": pin,
"location.isLive": "Active"
}
},
{
"$project": {
"delivery": "$location.delivery",
"dc": "$location.dc",
"midnight": "$location.midnight",
"isLive": "$location.isLive",
"_id": "$location._id",
"pincode": "$location.pincode",
"city": "$location.city"
}
}
]);
Example here

Related

How to filter out text fields in a complex query?

I've got a lot of doc filters on my UI (date ranges, checkboxes, input fields), so the query is generated dynamically - that's why I decided to create a boolean query, and push everything to must array. This is the example of my request:
const {
body: {
hits
}
} = await esclient.search({
from: filterQuery.page || 0,
size: filterQuery.limit || 1000,
index,
body: query
});
Checkboxes (I used additional bool.should inside must array) and date range work perfectly, but term/match filtering is not working at all:
{
"query": {
"bool": {
"must": [
{"match": { "issueNumber": "TEST-10" }}
]
}
}
}
The query above gives me all the documents from the index that contains "TEST" (with their scores), if I change match to term - it returns an empty array.
As my field is of a type 'text', I've also tried filter query - ES still gives all the documents with 'TEST' word:
{
"query": {
"bool": {
"must": [
{
"bool": {
"filter": {
"match": {"issueNumber": "TEST-10"}
}
}
}
]
}
}
}
This is how my hit looks like:
{
"_index" : "test_elastic",
"_type" : "_doc",
"_id" : "bj213hj2gghg213",
"_score" : 0.0,
"_source" : {
"date" : "2019-11-26T13:27:01.586Z",
"country" : "US",
"issueNumber" : "TEST-10",
}
Can someone give me input on how to filter the docs properly in complex query?
This is the structure of my index:
{
"test_elasticsearch" : {
"aliases" : { },
"mappings" : {
"properties" : {
"country" : {
"type" : "text"
},
"date" : {
"type" : "date"
},
"issueNumber" : {
"type" : "text"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1574759226800",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "PTDsdadasd-ERERER",
"version" : {
"created" : "7040299"
},
"provided_name" : "logs"
}
}
}
}
Ok, the problem is that your issueNumber field has not the right type, it should be keyword instead of text if your goal is to make exact searches on it. Same for country. Modify your mapping like this:
"properties" : {
"country" : {
"type" : "keyword"
},
"date" : {
"type" : "date"
},
"issueNumber" : {
"type" : "keyword"
}
}
Then reindex your data and your queries will work.

how to find x number of documents where one property matches but other are distinct

Ok, imagine a collection like this:
[
{
"_id" : ObjectId("5b5f76eb2bfe4a1e9c473bd2"),
"machine" : "NY-D800",
"level" : "Fatal",
},
{
"_id" : ObjectId("5b5f76eb2bfe4a1e9c473bd2"),
"machine" : "NY-D889",
"level" : "Fatal",
},
{
"_id" : ObjectId("5b5f76eb2bfe4a1e9c473bd2"),
"machine" : "NY-D889",
"level" : "Info",
},
{
"_id" : ObjectId("5b5f76eb2bfe4a1e9c473bd2"),
"machine" : "NY-D800",
"level" : "Fatal",
},
...
]
I want to find documents that have level set to 'Fatal' but I don't want to return duplicates (duplicate machine). So for example 'NY-D800' is listed twice with 'Fatal' so I would want it to be returned only once. Finally I would like to limit the values returned to 10 items.
Recapping:
level = 'Fatal'
only unique values determined by machine
limit to 10 docs
Is this possible with MongoDB, Mongoose?
I tried this:
Logs
.distinct({'level': 'Fatal'})
.limit(10)
.exec(function (err, response){
var result = {
status: 201,
message: response
};
if (err){
result.status = 500;
result.message = err;
} else if (!response){
result.status = 404;
result.message = err;
}
res.status(result.status).json(result.message);
});
You can first $match with the level "Fatal" and then apply $group with machine
Logs.aggregate([
{ "$match": { "level": "Fatal" }},
{ "$group": {
"_id": "$machine",
"level": { "$first": "$level" },
}},
{ "$limit": 10 },
{ "$project": { "machine": "$_id", "level": 1, "_id": 0 }}
])

Find existing object into an array in nodejs

Hi this is my collection i just want to look userId into subcriber array if both userId exist into the subcriber array than not create new collection return same channelId. If both userId not exist into subcriber array then create new document how can i search userids in an array.
this is my collection.
{
"_id" : ObjectId("58dd1013e973fc0004743443"),
"createdAt" : ISODate("2017-03-30T14:02:59.175Z"),
"updatedAt" : ISODate("2017-03-30T14:02:59.175Z"),
"timestamp" : "2017-03-30",
"channelId" : "CH-EU7D",
"createdById" : "58dcc3cd9a7a301308b62857",
"message" : "",
"subcriber" : [
{
"userId" : "58dcc3cd9a7a301308b62857",
"channelId" : "CH-EU7D",
"_id" : ObjectId("58dd1013e973fc0004743444"),
"status" : "accepted"
},
{
"userId" : "58dcc3ec9a7a301308b62859",
"channelId" : "CH-EU7D",
"_id" : ObjectId("58dd1013e973fc0004743445"),
"status" : "pending"
}
],
"__v" : 0
}
I have tried this but not working.
Channel.find({ 'subcriber.userId': b.userId }, { $and: [{ 'subcriber.userId': b.friendId }] }
In nodejs you can use JavaScript Array.prototype.some() method with your json array to test if there's any matching useId, you will need to write something like:
function checkUserId(array, userId) {
return array.some(function(element) {
return userId === element.userId;
});
}
This is a Demo snippet:
function checkUserId(array, userId) {
return array.some(function(element) {
return userId === element.userId;
});
}
var json = {
"_id": "58dd1013e973fc0004743443",
"createdAt": "2017-03-30T14:02:59.175Z",
"updatedAt": "2017-03-30T14:02:59.175Z",
"timestamp": "2017-03-30",
"channelId": "CH-EU7D",
"createdById": "58dcc3cd9a7a301308b62857",
"message": "",
"subcriber": [{
"userId": "58dcc3cd9a7a301308b62857",
"channelId": "CH-EU7D",
"_id": "58dd1013e973fc0004743444",
"status": "accepted"
},
{
"userId": "58dcc3ec9a7a301308b62859",
"channelId": "CH-EU7D",
"_id": "58dd1013e973fc0004743445",
"status": "pending"
}
]
};
//Check an existing userId
console.log(checkUserId(json.subcriber, "58dcc3ec9a7a301308b62859"));
//Check a non existing userId
console.log(checkUserId(json.subcriber, "58dcc3ec9a7a3000000000859"));
for this type of problem can use $elemMatch of mongodb.
db.getCollection('channels').find({subcriber:{"$elemMatch":{userId:"58dcc3cd9a7a301308b62857",userId:'58dcc3ec9a7a301308b62859'}}})

Updating array inside two object in mongod

I have a collection of the structure as follows:
collection name : "positions"
Structure
{
"_id" : "vtQ3tFXg8THF3TNBc",
"candidatesActions" : {
"sourced" : [ ],
},
"appFormObject" : {
"name" : "✶ mandatory",
"questions" : [
{
"qusId" : "qs-585494",
"type" : "simple",
"qus" : "Which was your previous company"
},
{
"qusId" : "qs-867766",
"type" : "yesNo",
"qus" : "Are you willing to relocate?",
"disqualify" : "true"
}
]
}
}
I want to update "qus" field of the above collection whose _id is "vtQ3tFXg8THF3TNBc" and "qusId" is "qs-585494".
Try following....
db.positions.update(
{_id: "vtQ3tFXg8THF3TNBc", "appFormObject.questions.qusId":"qs-585494"},
{$set:{"appFormObject.questions.$.qus": "this is updated value"}}
)
Use following query
db.positions.findAndModify({
query: { _id: "vtQ3tFXg8THF3TNBc", "appFormObject.questions.qusId":"qs-585494"} ,
update: { $set: { 'appFormObject.questions.$.qus': 'Brilliant Green' } },
});
Thanks

MongoDB Aggregate - Unwind, group and project

Using the collection Users, is it possible to retrieve the below unique list of organisations/owners? If this current set up isn't possible, is it possible to get the same results from two ID-linked collections with one query?
Currently, using Mongoose I can only retrieve the group of organisation names:
Current query
userModel.aggregate([
{ $unwind:'$organisations' }
, { $group: { name: '$organisations.name' } }
])
Users
{ "_id" : ObjectId("53f4a94e7c88310000000001"),
"email" : "bob#example.com",
"organisations" : [
{
"name" : "OrgOne",
"isOwner" : true
}
]
},
{ "_id" : ObjectId("53f4a94e7c88310000000002"),
"email" : "ash#something.com",
"organisations" : [
{
"name" : "OrgOne"
}
]
},
{ "_id" : ObjectId("53f4a94e7c88310000000003"),
"email" : "george#hello.com",
"organisations" : [
{
"name" : "OrgTwo",
"isOwner" : true
}
]
}
Results
{ "orgName" : "OrgOne",
"owner" : 53f4a94e7c88310000000001
},
{ "orgName" : "OrgTwo",
"owner" : 53f4a94e7c88310000000003
}
Thanks in advance, Nick
Seems like an odd use of aggregation to me, but possibly there are several "organisations" per user here, so I guess I'll continue:
userModel.aggregate(
[
{ "$match": { "organisations.isOwner": true } },
{ "$unwind": "$organisations" },
{ "$match": { "organisations.isOwner": true } },
{ "$group": {
"_id": "$organisations.name",
"owner": { "$first": "$_id" }
}}
],
function(err,result) {
}
);
If there is more than one owner and you need some precedence then you can implement a $sort before the group. Or otherwise just $project rather than group in order to get everyone.

Categories

Resources