How to write OR query with elastic search in node js - javascript

I have my document like this
Sample document,
[
{
"_index": "xpertdox",
"_type": "disease",
"_id": "Ectopic Heartbeat",
"_score": 24.650267,
"_source": {
"category": "Condition",
"name": "Ectopic Heartbeat",
"dui": "D005117",
"url_name": "Extrasystole"
}
},
This is my sample document.
if (req.param('disease')) {
searchString = req.param('disease');
filterQuery = { Category:
['disease','Condition','speciality','pharm','medicine'] };
} else if (req.param('docorhosp')) {
searchString = req.param('docorhosp');
filterQuery = { Category: ['hospital', 'doctor'] };
} else if (req.param('speciality')) {
searchString = req.param('speciality');
filterQuery = { Category: ['speciality'] };
}
client.search({
index: 'xpertdox',
type: 'disease',
size: 20,
body: {
query: {
must: {
match: {
name: {
query: searchString,
fuzziness: 2,
operator: "or"
}
}
},
filter : {
terms : filterQuery
}
}
}
}).then(function (resp) {
var data = resp.hits.hits;
if (isFromSsr) {
data = helper.prepareSearchDataForSsr(data);
}
res.json(data);
});
I am matching my parameter with name,but here I want to filter records only whose category is either 'doctor' or 'hospital'.How can devolope my query so to get my requirement..

Try this:
client.search({
index: 'dox',
type: 'disease',
size: 20,
body: {
query: {
must: {
match: {
name: {
query: req.param('disease'),
fuzziness: 2,
operator: "or"
}
}
},
filter: {
terms: {
category: ['hospital', 'doctor']
}
}
}
}
})

Related

unable to load nested object data in mongoose database properly

The issue I am facing is that even though I am able to load the data in the database but the desired result is different from what is being returned.
The issue is that whenever I am running for loop the qn variable is inserted twice but need it only once.
Please if someone can help me resolve this issue.
userProject.js
router.post('/notification/check/upload/survey' , async (req,res) => {
//const taginsert = [];
const mcq = [];
//const newData = {};
//const o = {};
console.log(req.body);
for(var i=0; i<=req.body.questions.length-1;i++) {
// newData = {
// qn: req.body.questions[i].qn
// }
for(var j=0; j<=req.body.questions[i].options.length-1;j++){
const o =
{
qn: req.body.questions[i].qn,
//{
options: [{
option: req.body.questions[i].options[j].option,
totalValues: req.body.questions[i].options[j].totalValues
}]
}
// newData.options = o;
// newData.push(o);
mcq.push(o);
}
}
//mcq = newData;
const check = new userCampaignSurvey({
userId: req.body.userId,
status: 'Pending',
notification_type:req.body.notification_type,
questions: mcq
})
check.save((err,p) => {
if(err) {
res.status(500).send(err);
}
res.status(201).send(p);
})
})
model.js
userId:
{
type: Number,
required: true,
trim: true
},
notification_id:
{
type: Number,
},
notification_type:
{
type: Number,
required: true,
},
status:
{
type: String,
required: true
},
questions: [
{
qn: {
type: String,
required: true
},
options: [
{
option: {
type: String
},
totalViews: {
type:Number
}
}
]
},
],
created_at: {
type: Date,
required: true,
default: Date.now(),
},
});
result received
{
"userId": 1,
"notification_type": 1,
"status": "Pending",
"questions": [
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Adidas",
"_id": "639064c9ec215f2cd1b2b15d"
}
],
"_id": "639064c9ec215f2cd1b2b15c"
},
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Reebok",
"_id": "639064c9ec215f2cd1b2b15f"
}
],
"_id": "639064c9ec215f2cd1b2b15e"
}
],
"created_at": "2022-12-07T10:02:48.442Z",
"_id": "639064c9ec215f2cd1b2b15b",
"__v": 0
}
expected result
{
"userId": 1,
"status": "Pending",
"notification_type": 1,
"questions": [
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Adidas",
"totalViews": 20
},
{
"option": "Reebok",
"totalViews": 10
}
]
}
]
}

Mongoose add to array of nested array if exists create otherwise

i'm trying to accomplish the following in mongoose:
Say i have the following collection
{
"_id": {
"$oid": "111"
},
"email": "xxx#mail.com",
"givenName": "xxx",
"familyName": "xxx",
"favoriteProducts": [{
"soldTo": "33040404",
"skus": ["W0541", "W2402"]
}, {
"soldTo": "1223",
"skus": ["12334"]
}]
}
i want to be able to add a sku to the favorite products array based on soldTo and _id.
When doing this there are two possible scenarios.
a. There is already an object in favoriteProducts with the given soldTo in which case the sku is simply added to the array.(for example add sku '12300' to soldTo '1223' for id '111')
b. There is no object with the given soldTo yet in which case this object need to be created with the given sku and soldTo. (for example add sku '123' to soldTo '321' for id '111')
so far i've done this but i feel like there is a way to do it in one query instead.
private async test() {
const soldTo = '1223';
const sku = '12300';
const id = '111';
const hasFavoriteForSoldTo = await userModel.exists({
_id: id,
'favoriteProducts.soldTo': soldTo,
});
if (!hasFavoriteForSoldTo) {
await userModel
.updateOne(
{
_id: id,
},
{ $addToSet: { favoriteProducts: { skus: [sku], soldTo } } },
)
.exec();
} else {
await userModel
.updateOne(
{
_id: id,
'favoriteProducts.soldTo': soldTo,
},
{ $addToSet: { 'favoriteProducts.$.skus': sku } }
)
.exec();
}
}
Use update-documents-with-aggregation-pipeline
Check out mongo play ground below. Not sure you want Output 1 or Output 2.
Output 1
db.collection.update({
_id: { "$oid": "111222333444555666777888" }
},
[
{
$set: {
favoriteProducts: {
$cond: {
if: { $in: [ "1223", "$favoriteProducts.soldTo" ] },
then: {
$map: {
input: "$favoriteProducts",
as: "f",
in: {
$cond: {
if: { $eq: [ "1223", "$$f.soldTo" ] },
then: { $mergeObjects: [ "$$f", { skus: [ "12300" ] } ] },
else: "$$f"
}
}
}
},
else: {
$concatArrays: [ "$favoriteProducts", [ { skus: [ "12300" ], soldTo: "1223" } ] ]
}
}
}
}
}
],
{
multi: true
})
mongoplayground
Output 2
db.collection.update({
_id: { "$oid": "111222333444555666777888" }
},
[
{
$set: {
favoriteProducts: {
$cond: {
if: { $in: [ "1223", "$favoriteProducts.soldTo" ] },
then: {
$map: {
input: "$favoriteProducts",
as: "f",
in: {
$cond: {
if: { $eq: [ "1223", "$$f.soldTo" ] },
then: {
$mergeObjects: [
"$$f",
{ skus: { $concatArrays: [ [ "12300" ], "$$f.skus" ] } }
]
},
else: "$$f"
}
}
}
},
else: {
$concatArrays: [ "$favoriteProducts", [ { skus: [ "12300" ], soldTo: "1223" } ] ]
}
}
}
}
}
],
{
multi: true
})
mongoplayground

Mongodb find all and update all but one

so i have this db lookup
const channelLinkId = "123456"
location = await Locations.find({
services: {
$elemMatch: {
credentials: channelLinkId,
},
},
});
and this is what im getting back from that db look up an array of db objects.
[
{
name: "test",
services: {
credentials: "123456"
}
}
{
name: "test1",
services: {
credentials: "123456"
}
},
{
name: "test1",
services: {
credentials: "123456"
}
}
]
the result i want is to have from this db lookup is to have the second and third values of this array to have credentials empty.
[
{
name: "test",
services: {
credentials: "123456"
}
}
{
name: "test1",
services: {
credentials: ""
}
},
{
name: "test1",
services: {
credentials: ""
}
}
]
It is not possible with single update query,
find one document using finOne() and select only _id if other fields are not required
const channelLinkId = "123456"
let location = await Locations.findOne({ "services.credentials": channelLinkId }, { _id: 1 });
update other document's credentials that is not above found document
await Locations.updateMany(
{ _id: { $ne: location._id }, "services.credentials": channelLinkId },
{ $set: { "services.credentials": "" } }
);

How can I map json to specific format in TypeScript?

I have the below json
[
{
"fullName":"Mariem",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"endHour":"1330",
"motif":"maladie"
},
{
"fullName":"Mariem",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"endHour":"1800",
"motif":"renuion"
},
{
"fullName":"Mariem",
"startDate":"1917-05-25",
"endDate":"1917-05-25",
"endHour":"1600",
"motif":"renuion"
},
{
"fullName":"Jack",
"startDate":"0017-01-25",
"endDate":"0017-01-25",
"endHour":"1030",
"motif":null
}
]
Who can i map it like the below json, grouping the objects by fullName, startDate and endDate, and add an array of objects contients the endDate and motif.
[
{
"fullName":"Mariem ",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"data":[
{
"endHour":"1330",
"motif":"maladie"
},
{
"endHour":"1800",
"motif":"renuion"
}
]
},
{
"fullName":"Mariem ",
"startDate":"1917-05-25",
"endHour":"1917-05-25",
"data":[
{
"endHour":"1600",
"motif":"renuion"
}
]
},
{
"fullName":"Jack",
"startDate":"0017-01-25",
"endDate":"0017-01-25",
"data":[
{
"endHour":"1030",
"motif":null
}
]
}
]
If I understood your question correctly you are looking for something like this:
interface SomeObj {
fullName: string,
startDate: string,
endDate: string,
endHour: string,
motif: string
}
interface Time {
endHour:string,
motif:string
}
interface MappedObj {
fullName: string,
startDate: string,
endHour: string,
data: Time[]
}
function mapToFormat(o: SomeObj[]): MappedObj[] {
return o.map(item => {
return {
fullName: item.fullName,
startDate: item.startDate,
endHour: item.endHour,
data: [
{
endHour: item.endHour,
motif: item.motif
}
]
}
})
}
You have errors in both your sample input and output(swapping endHour and endDate).
Here is a quick solution:
const map = new Map();
elements.forEach(item => {
const key = `${item.fullName}+${item.startDate}+${item.endDate}`;
if (!map.has(key)) {
map.set(key, {
fullName: item.fullName,
startDate: item.startDate,
endDate: item.endDate,
data: []
});
}
map.get(key).data.push({
endHour: item.endHour,
motif: item.motif
});
});
const result = Array.from(map.values());
With input of:
const elements = [
{
"fullName":"Mariem",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"endHour":"1330",
"motif":"maladie"
},
{
"fullName":"Mariem",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"endHour":"1800",
"motif":"renuion"
},
{
"fullName":"Mariem",
"startDate":"1917-05-25",
"endDate":"1917-05-25",
"endHour":"1600",
"motif":"renuion"
},
{
"fullName":"Jack",
"startDate":"0017-01-25",
"endDate":"0017-01-25",
"endHour":"1030",
"motif":null
}
];
The result variable will have the value of:
[
{
"fullName":"Mariem",
"startDate":"1917-04-25",
"endDate":"1917-04-26",
"data":[
{
"endHour":"1330",
"motif":"maladie"
},
{
"endHour":"1800",
"motif":"renuion"
}
]
},
{
"fullName":"Mariem",
"startDate":"1917-05-25",
"endDate":"1917-05-25",
"data":[
{
"endHour":"1600",
"motif":"renuion"
}
]
},
{
"fullName":"Jack",
"startDate":"0017-01-25",
"endDate":"0017-01-25",
"data":[
{
"endHour":"1030",
"motif":null
}
]
}
]

MongoDB move element of sub-document to another sub-document

I need to change my schema
const dataSchema = new Schema({
trackingPrice: [{
timeCheck: { type: Date, default: Date.now },
lowestPrice: Number,
salePrice: Number,
saleRank: Number
}]
})
to this
const dataSchema = new Schema({
trackingPrice: [{
timeCheck: { type: Date, default: Date.now },
lowestPrice: Number,
salePrice: Number
}],
trackingRank: [{
timeCheck: { type: Date, default: Date.now },
saleRank: Number
}]
})
How can I transfer my data from one to another under document and then delete "saleRank"?
Based on this very good answer, the cursor in your case would be derived from running the aggregate pipeline:
const pipeline = [
{
"$project": {
"trackingPrice": {
"$map": {
"input": "$trackingPrice",
"as": "el",
"in": {
"timeCheck": "$$el.timeCheck",
"lowestPrice": "$$el.timeCheck",
"salePrice": "$$el.salePrice"
}
}
},
"trackingRank": {
"$map": {
"input": "$trackingPrice",
"as": "el",
"in": {
"timeCheck": "$$el.timeCheck",
"saleRank": "$$el.saleRank"
}
}
}
}
}
];
const cursor = Data.aggregate(pipeline).exec();
Running the bulk update:
let bulkUpdateOps = [];
cursor.then(results => {
results.forEach(doc => {
const { _id, trackingPrice, trackingRank } = doc;
bulkUpdateOps.push({
"updateOne": {
"filter": { _id },
"update": { "$set": { trackingPrice, trackingRank } },
"upsert": true
}
});
});
if (bulkUpdateOps.length === 1000) {
bulkUpdateOps = [];
return Data.bulkWrite(bulkUpdateOps);
}
}).then(console.log).catch(console.error);
if (bulkUpdateOps.length > 0) {
Data.bulkWrite(bulkUpdateOps).then(console.log).catch(console.error);
}
The best way I see is to find all of them, and foreach one create a new one
I'm using mongoose by the way
dataSchema.find({}, (err,all) => {
var array = [];
all.foreach( (ds) => {
array.push({
trackingPrice: ds.trackingPrice,
trackingRank: //whatever way you want to update the old data
})
dataSchema.remove({}).exec(() => {
array.foreach((a) => {
var toadd = new dataSchema({
trackingPrice:a.trackingPrice,
trackingRank:a.trackingRank});
toadd.save();
})
})
})}
);

Categories