Mongodb find all and update all but one - javascript

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": "" } }
);

Related

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

Next.js: getStaticPaths for nested dynamic routes

Imagine you have this data structure:
const data = {
posts: [{
id: 1,
title: "Post 1"
slug: "post-1"
}, {
id: 2,
title: "Post 2"
slug: "post-2"
}],
comments: [{
id: 1,
postId: "post-1",
text: "Comment 1 for Post 1"
}, {
id: 2,
postId: "post-1",
text: "Comment 2 for Post 1"
}, {
id: 3,
postId: "post-2",
text: "Comment 1 for Post 2"
}]
}
An you have the following route /posts/[postId[/[commentId]
so the Next.js structure folder is: posts/[postId]/[commented].js
Then you need to generate the static paths for this routes.
I'm coded the following:
export async function getStaticPaths() {
const { posts, comments } = data
const paths = posts.map((post) => {
return comments
.filter((comment) => comment.postId === post.slug)
.map((comment) => {
return {
params: {
postId: post.slug,
commentId: comment.id
}
}
})
})
}
But it's not working. The throwed error was:
Error: Additional keys were returned from `getStaticPaths` in page "/clases/[courseId]/[lessonId]". URL Parameters intended for this dynamic route must be nested under the `params` key, i.e.:
return { params: { postId: ..., commentId: ... } }
Keys that need to be moved: 0, 1.
How I can "map" or "loop" the data to a proper returned format?
Thanks in advance!
The problem seems to be that your returning this from getStaticPaths data with a wrong shape:
[
[ { params: {} }, { params: {} } ],
[ { params: {} } ]
]
The correct shape is:
[
{ params: {} },
{ params: {} },
{ params: {} }
]
Just tried this and it works.
export async function getStaticPaths() {
const paths = data.comments.map((comment) => {
return {
params: {
postId: comment.postId,
commentId: comment.id
}
}
});
console.log(paths);
return {
paths,
fallback: false
}
};
It generates 3 urls:
/posts/post-1/1
/posts/post-1/2
/posts/post-2/3
Is that what you need?
Like mention #Aaron the problem is for double array of filter y el map.
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } }
],
fallback: ...
}
Doc 📚 ➡ https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required

Loopback findOrCreate creates new records even if there is an existing record

As per my understanding of the loopback documentation Persistedmodel.findOrCreate should find a model according to the query and return it, or create a new entry in the database if the model does not exist.
What I have noticed in my case is that it creates a new entry irrespective of whether there is an existing entry.
Not sure what I am missing. Here is my code:
teams-joined.json
{
"name": "teamsJoined",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"teamID": {
"type": "string",
"required": true
},
"playerID":{
"type":"string",
"required":true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
teams-joined.js
let queryThatWorks = {where:{
and: [
{teamID: teamID}
]
}
};
let query = {where:{
and: [
{teamID: teamID},
{playerID: req.currentUser.id},
],
}
};
let joinTeamsData = {
teamID: teamID,
playerID: req.currentUser.id,
};
console.log(query.where,'query');
teamsJoined.findOrCreate(query, joinTeamsData,
function(err, data, created) {
console.log(data,created);
});
When I cal the API multiple times, this is what I get
{ and:
[ { teamID: 'bf36e0-93a5-11e8-a8f4-9d86f4dd79ee' },
{ playerID: '5b20887bb6563419505c4590' } ] } 'query'
{ teamID: 'bf36e0-93a5-11e8-a8f4-9d86f4dd79ee',
playerID: '5b20887bb6563419505c4590',
id: 5b61798534fa410d2b1d900a } 'data'
true 'created'
{ and:
[ { teamID: 'bf36e0-93a5-11e8-a8f4-9d86f4dd79ee' },
{ playerID: '5b20887bb6563419505c4590' } ] } 'query'
{ teamID: 'bf36e0-93a5-11e8-a8f4-9d86f4dd79ee',
playerID: '5b20887bb6563419505c4590',
id: 5b61798634fa410d2b1d900b } 'data'
true 'created'
I expected it to return false for created and just return the existing data.
This works fine when I use the 'queryThatWorks' query from my code sample.
You don't need to use and operator in your where clause. See findOrCreate.
{ where: { teamID: teamID, playerID: req.currentUser.id } }
You can include your data into your filter like that:
{ where: joinTeamsData }
To return specific fields in your return statement, you can use the fields option in your query.
Finally, try this:
let data = {
teamID: teamID,
playerID: req.currentUser.id,
};
let filter = { where: data };
teamsJoined.findOrCreate(filter, data,
function(err, instance, created) {
console.log(instance, created);
}
);

Mongo query search updateOne $elemmatch

I'm having trouble updating my database. I have a surveys collection and each document is as follows:
{
"_id": {
"$oid": "5aaf4f7984521736d88db4bb"
},
"title": "4242 ",
"body": "4242 ",
"subject": "4242 ",
"recipients": [
{
"email": "a#gmail.com",
"responded": false,
"_id": {
"$oid": "5ab04084be3c1529bcbdcd6e"
}
},
{
"email": " b#gmail.com",
"responded": false,
"_id": {
"$oid": "5ab04084be3c1529bcbdcd6d"
}
},
{
"email": " c#gmail.com",
"responded": false,
"_id": {
"$oid": "5ab04084be3c1529bcbdcd6c"
}
},
{
"email": " d#gmail.com",
"responded": false,
"_id": {
"$oid": "5ab04084be3c1529bcbdcd6b"
}
},
{
"email": " e#gmail.com",
"responded": false,
"_id": {
"$oid": "5ab04084be3c1529bcbdcd6a"
}
}
],
"_user": {
"$oid": "5aa5edbf8887a21af8a8db4c"
},
"dateSent": {
"$date": "2018-03-20T00:11:55.943Z"
},
"yes": 0,
"no": 0,
"__v": 0
}
I'm calling this on my back-end using mongoose to try and update my database whenever a user responded to a survey.
const Survey = mongoose.model('surveys');
Survey.updateOne(
{
_id: surveyId,
recipients: {
$elemMatch: { email: email, responded: false }
}
},
{
$inc: { [choice]: 1 },
$set: { 'recipients.$.responded': true }
}
).exec();
But the update is only successful when the query matches the first object in the recipients array. For example, this would work. The query successfully updates the survey document and the recipient subdocument.
Survey.updateOne(
{
_id: surveyId,
recipients: {
$elemMatch: { email: "a#gmail.com", responded: false }
}
},
{
$inc: { [choice]: 1 },
$set: { 'recipients.$.responded': true }
}
).exec();
But this doesn't work
Survey.updateOne(
{
_id: surveyId,
recipients: {
$elemMatch: { email: "b#gmail.com", responded: false }
}
},
{
$inc: { [choice]: 1 },
$set: { 'recipients.$.responded': true }
}
).exec();
These are my schemas
const surveySchema = new Schema({
title: String,
body: String,
subject: String,
recipients: [RecipientSchema],
yes: { type: Number, default: 0 },
no: { type: Number, default: 0 },
_user: { type: Schema.Types.ObjectId, ref: 'User' },
dateSent: Date,
lastResponded: Date
});
const recipientSchema = new Schema({
email: String,
responded: { type: Boolean, default: false }
});
When I use node to try to query the database manually, it also only returns the survey when the query matches the first recipient subdocument.
This successfully finds the survey and returns it.
Survey.find(
{
_id: "5aaf4f7984521736d88db4bb",
recipients: {
$elemMatch: {
email: "a#gmail.com",
responded: false
}
}
}).then(console.log)
These don't
Survey.find(
{
_id: "5aaf4f7984521736d88db4bb",
recipients: {
$elemMatch: {
email: "b#gmail.com",
responded: false
}
}
}).then(console.log)
Survey.find(
{
_id: "5aaf4f7984521736d88db4bb",
recipients: {
$elemMatch: {
email: "c#gmail.com",
responded: false
}
}
}).then(console.log)
I have been trying to look up how $elemMatch works and someone told me that I can't query the properties of objects inside the recipients array, and that I can only query its IDs.
The problem is that you're storing the subsequent emails without trimming them, as you can see only the first email is properly trimmed, but the rest have a blank space at the beginning , making the query return nothing.

How to write OR query with elastic search in node js

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']
}
}
}
}
})

Categories