Targeting Specific Array Element with Assignment Destructuring - javascript

I am using some assignment destructuring in my MongoDB/Node backend in order to handle some post-processing. I'm just trying to understand how this destructuring works, and if, in the case of an array of multiple elements and nested arrays, if I can input the element I want to target.
Take for instance this code:
services: [
,
{
history: [...preSaveData]
}
]
} = preSaveDocObj;
My assumption is that the "," in "services" for the above code will default to looking at the first element in the array. Correct?
Now, if I have a document structure that looks like this (see below), and I know I want to target the "services" element where "service" is equal to "typeTwo", how would I do that?:
{
_id: 4d39fe8b23dac43194a7f571,
name: {
first: "Jane",
last: "Smith"
}
services: [
{
service: "typeOne",
history: [
{ _id: 121,
completed: true,
title: "rookie"
},
{ _id: 122,
completed: false,
title: "novice"
}
]
},
{
service: "typeTwo",
history: [
{ _id: 135,
completed: true,
title: "rookie"
},
{ _id: 136,
completed: false,
title: "novice"
}
]
}
]
}
How can I edit this code (see below) to specifically target the "services" array where "service" is equal to "typeTwo"?
services: [
,
{
history: [...preSaveData]
}
]
} = preSaveDocObj;

Don't overdestructure, just find:
const { history: [...preSavedData] } = doc.services.find(it => it.serice === "typeTwo");

Related

How do I pick then sort MongoDB documents and then find next document to mine?

I have a collection of documents, which I need to first narrow down by set criteria, then sort alphabetically by string value inside those documents — let's say that's a "search result". I then need to find document that matches a given _id and then pick a document next to it (before or after) from the above "search result".
Background:
I use mongoose to query my database via Node.js.
I have a set of "special sections" in my blog that are comprised of all the articles that must have three particular conditions associated within the keys in the document. I can get the list of articles belonging to said section like so:
const specialSectionListQuery = Article.find({
tag: { $ne: "excluded" },
[`collections.cameras`]: { $exists: true },
status: "published",
})
To finish creating the "special section," I must sort the documents alphabetically via their title attribute:
.sort({ [`collections.cameras.as.title`]: "asc" })
Now I want to add a link to "next article within the same special section" at the bottom of such articles. I know _id and any other value needed from the current article. The above query gives me an ordered list of documents within the section so I can easily find it within that list specialSectionListQuery.findOne({ _id: "xxx" }).exec().
However, I need to find the next article within the above list. How do I do that?
My attempts thus far:
I tried to create article list via aggregation, which led me nowhere (I simply made my app do exactly the same thing — make a list for a "special sectin"):
Article.aggregate([
{
$match: {
tag: { $ne: "excluded" },
[`collections.cameras`]: { $exists: true },
status: "published",
},
},
{
$sort: {
[`collections.cameras.as.title`]: 1,
},
}
]).exec()
But I can't for the life of me figure out how to iterate to the next document in the list properly.
I have thought of saving the list in Node.js memory (variable) and then finding what I need via JavaScript but that can't be scalable.
I have considered creating a new collection and saving the above list there but that would require me to either 1) do it every time a document is altered/added/deleted via Node.js — which is a lot of code and it may break if I interact with database another way 2) rebuild the colleciton every time I run the query, but that feels like it'll lack in performance.
Please help and thank you!
P.S.:
Example collection which should cover most of the cases I'm looking to solve for:
[
{
_id: 1,
name: "Canon",
collections: { cameras: { as: { title: "Half-Frame" } } },
tag: "included",
status: "published"
},
{
_id: 2,
name: "Pentax",
collections: { cameras: { as: { title: "Full-Frame" } } },
tag: "included",
status: "published"
},
{
_id: 3,
name: "Kodak",
collections: { film: { as: { title: "35mm Film" } } },
tag: "included",
status: "published"
},
{
_id: 4,
name: "Ricoh",
collections: { cameras: { as: { title: "Full-Frame" } } },
tag: "included",
status: "published"
},
{
_id: 5,
name: "Minolta",
collections: { cameras: { as: { title: "Half-Frame Review" } } },
tag: "excluded",
status: "published"
},
{
_id: 4,
name: "FED",
collections: { cameras: { as: { title: "Full-Frame" } } },
tag: "included",
status: "draft"
}
]
One thing you can try is to extend your $sort by adding _id so that it always returns documents in deterministic order:
{
$sort: {
"collections.cameras.as.title": 1,
_id: 1
}
},
{
$limit: 1
}
Once your first query returns the document with _id: 2 and collections.cameras.as.title: Full-Frame, you can use below query to get subsequent document:
{
$match: {
$and: [
{
tag: { $ne: "excluded" },
"collections.cameras": { $exists: true },
status: "published",
},
{
$or: [
{
$and: [
{ "collections.cameras.as.title": { $eq: "Full-Frame" } },
{ "_id": { $gt: 2 } }
]
},
{ "collections.cameras.as.title": { $gt: "Full-Frame" } }
]
}
]
}
},
{
$sort: {
"collections.cameras.as.title": 1,
_id: 1
}
},
{
$limit: 1
}
In this case due to deterministic $sort you can exclude previously found document by adding additional filtering criteria and the order should be preserved.
Mongo Playground

Reduce mongodb aggregation with condition

I have an array of objects call "extra" with different properties: some objects have "plus" and some haven't.
I want to create inside this "extra" array, 2 different arrays one called "cheap" with all the object that don't have the "plus" property and one called "exp" with only the objects with the "plus" property.
I think I can use the $reduce method in mongodb aggregate with $concatArrays and check with $cond if the property plus exists or not.
Something like that:
Data example:
{
extra: [
{
description: "laces",
type: "exterior",
plus: '200'
},
{
description: "sole",
type: "interior"
},
{
description: "logo",
type: "exterior"
},
{
description: "stud",
type: "exterior",
plus: '450'
}
],
}
{
$project: {
extra: {
$reduce: {
input: ['$extra'],
initialValue: {cheap: [], exp: []},
$cond: {
if: {$eq: ['$$this.plus', null]},
then: {
in: {
cheap: {
$concatArrays: ['$$value.cheap', '$$this'],
},
},
},
else: {
in: {
exp: {
$concatArrays: ['$$value.exp', '$$this'],
},
},
},
},
},
},
},
}
It doesn't work...I tried many ways or writing the $cond part without luck.
I can't figure it out.
Thank you all.
K.
Apart from some minor syntax issues you've had another problem is your understand of the $ne operator.
In this case you expect a missing value to be equal to null, this is not how Mongo works. so for a document:
{ name: "my name" }
The aggregation query:
{ $cond: { $eq: ["$missingField", null] } }
Will not give true as you expect as missing is not equal to null. I took the liberty to fix the syntax issues you've had, this working pipeline is the way to go:
db.collection.aggregate([
{
$project: {
extra: {
$reduce: {
input: "$extra",
initialValue: {
cheap: [],
exp: []
},
in: {
cheap: {
"$concatArrays": [
"$$value.cheap",
{
$cond: [
"$$this.plus",
[],
[
"$$this"
],
]
}
]
},
exp: {
"$concatArrays": [
"$$value.exp",
{
$cond: [
"$$this.plus",
[
"$$this"
],
[]
]
}
]
}
}
},
},
},
}
])
Mongo Playground
One thing to note is that $cond evaluates the plus field, meaning if the field does exist with a null value or a 0 value then it will consider this document matched for the cheap array. This is something to consider and change in case these are possible.

how to get value of an attribute if we are not sure about the position of the attribute in an array in react native

Consider the array which I get as response from API call. what if the position of any one of the attributes gets changed and I want to get the attribute salary/id/idProperty i.e., If I am not sure about attribute position how can get its value without hard coding the array with index?
var arr = [
{
id: "alex",
idProperty: {
args: [
{
name: "alex_name"
},
{
salary: "16L"
}
]
}
},
{
id: "john",
idProperty: {
args: [
{
name: "john_name"
},
{
salary: "14L"
}
]
}
}
];

Reading the nested object in the nested object

My problem is reading properties of nested object, which is inside other nested object.
GraphQL
type Mapping {
id: ID!
partnerSegmentId: ID!
ctSegmentId: CtSegment!
}
type PartnerSegment {
id: ID!
name: String!
platformId: Int!
partner: Partner!
}
type Partner {
id: ID!
name: String!
}
Once I try to query it like:
{
allMappings {
partnerSegmentId {
id
name
partner {
id
}
}
}
}
I recieve:
{
"data": {
"allMappings": [
null
]
},
"errors": [
{
"message": "Cannot return null for non-nullable field Partner.name.",
"locations": [
{
"line": 8,
"column": 9
}
],
"path": [
"allMappings",
0,
"partnerSegmentId",
"partner",
"name"
]
}
]
}
Mapping schema
const mappingSchema = new mongoose.Schema(
{
partnerSegmentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'PartnerSegment',
required: [true, 'Mapping must have partner segment id.']
},
ctSegmentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'CtSegment',
required: [true, 'Mapping must have CT segment id.']
}
},
{ timestamps: true }
);
I tried to read separately Partner, PartnerSegment and Mapping models. All works fine. Any idea where i should search source of the problem? I've checked mongodb docs and ids looks okay. I suppose it's fault of my model.
If you would like to take a closer look it's project repo.
SOLUTION:
Garbage Id in the return value was caused by not working populate in the nested entity. The way I managed to solve the problem:
const allMappings = () =>
Mapping.find({})
.populate('user')
.populate('ctSegment')
.populate({
path: 'partnerSegment',
populate: {
path: 'partner'
}
})
.exec();

Search for a specific item in an array of objects and query if an attribute exists

Sample data:
{
_id: '1234',
games: [{
name: 'World of Warcraft',
lastLogin: ISODate(),
subscriptions: ['56', '78']
}, {
name: 'Starcraft II',
lastLogin: ISODate()
}]
}
Essentially, I want to find everyone that does not have a "subscriptions" field for a given game. I can't quite figure out a good way to do it.
Players.update({
'games.name': 'World of Warcraft',
'games.$.subscriptions': { $exists: false }
}, {
$set: { 'games.$.subscriptions': GLOBAL_SUB }
});
How do you query an array of elements for an attribute and the existence of a field?
Use $elemMatch when you want to match multiple terms on the same array element:
Players.update({
games: { $elemMatch: {
name: 'World of Warcraft',
subscriptions: { $exists: false }
}}
}, {
$set: { 'games.$.subscriptions': GLOBAL_SUB }
});

Categories