How to fetch particular object in a document of collection mongoDB? - javascript

I have this document in a collection. I want to fetch a particular product object which matches the query. I have a const query that fetches the product slug from the URL. There are product slugs defined in the database. What I want is prop product should contain only that object which matches the product slug.
MongoDB data
{
"productListing": {
"filters": [
{
"id": "brand",
"name": "Brands",
"options": [
{ "value": "Casio", "label": "Casio", "checked": false },
{ "value": "Yamaha", "label": "Yamaha", "checked": false }
]
}
],
"products": [
{
"sku": "KEY-CAS-001-GRN",
"product_brand": "Casio",
"product_name": "Casio SA-46 32 Mini Keys Musical Keyboard (Black/Green)",
"product_slug": "casio-sa-46-32-mini-keys-musical-keyboard"
},
{
"sku": "KEY-CAS-002-GRY",
"product_brand": "Casio",
"product_name": "Casio SA-47A Electronic Keyboard, Black (32 Keys)",
"product_slug": "casio-sa-47a-mini-keys-electronic-keyboard"
},
]
}}
product.js
export async function getServerSideProps(context) {
context.res.setHeader(
'Cache-Control',
'public, s-maxage=20, stale-while-revalidate=59'
)
var query = { product_slug: context.params.productslug };
const { db } = await connectToDatabase();
const result = await db
.collection("portable_keyboards").find({})
if (!result) {
return {
notFound: true,
}
}
return {
props: {
product: JSON.parse(JSON.stringify(result)),
},
};
}
export default function Product({ product }) {
//rest of the code
}

Related

fetching from svelte store returns [object, object]

when I fetch this array and return it in the HTML I keep getting [object, object] or undefined. does anyone know if it's because of something I'm not defining in my svelte store?
For now, I'm just trying to get the name from the API.
here is the "league-store.js"
import { writable } from "svelte/store";
export const leagueStore = writable([]);
const fetchLeagues = async () => {
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': 'API_KEY',
'X-RapidAPI-Host': 'v3.football.api-sports.io'
}
}
const url = `https://v3.football.api-sports.io/leagues?season=2022`;
const res = await fetch(url, options);
const data = await res.json();
const loadedLeagues = data.response.map((data) => {
return {
leagues: data
}
});
leagueStore.set(loadedLeagues);
}
fetchLeagues();
The +page.svelte
<script>
import { leagueStore } from "../../stores/league-stores";
console.log($leagueStore)
</script>
<div class="absolute top-[80px] right-0 w-[85vw] p-6">
{#each $leagueStore as leagues}
<p>{leagues}</p>
{/each}
</div>
and lastly the API im calling from as an example of the parameters
{
"get": "leagues",
"parameters": {
"season": "2022"
},
"errors": [],
"results": 815,
"paging": {
"current": 1,
"total": 1
},
"response": [
{
"league": {
"id": 351,
"name": "4. liga - Divizie B",
"type": "League",
"logo": "https://media.api-sports.io/football/leagues/351.png"
},
"country": {
"name": "Czech-Republic",
"code": "CZ",
"flag": "https://media.api-sports.io/flags/cz.svg"
},
"seasons": [
{
"year": 2022,
"start": "2022-08-05",
"end": "2023-06-10",
"current": true,
"coverage": {
"fixtures": {
"events": true,
"lineups": false,
"statistics_fixtures": false,
"statistics_players": false
},
"standings": true,
"players": false,
"top_scorers": false,
"top_assists": false,
"top_cards": false,
"injuries": false,
"predictions": true,
"odds": false
}
}
]
}
const loadedLeagues = data.response.map((data) => {
return {
leagues: data
}
});
Here data is an object of this form
{
"league": {
"id": 351,
"name": "4. liga - Divizie B",
"type": "League",
"logo": "https://media.api-sports.io/football/leagues/351.png"
},
"country": {
"name": "Czech-Republic",
"code": "CZ",
"flag": "https://media.api-sports.io/flags/cz.svg"
},
...
}
You could either map this to objects holding only the fields you need or use as is
const res = await fetch(url, options);
const data = await res.json();
leagueStore.set(data.response);
and access the fields like this
<div>
{#each $leagueStore as league}
<p>{league.league.name} - {league.country.name}</p>
{/each}
</div>
Since you tagged Sveltekit and are using an API key you might want to move the fetch logic to a page.server.js file or endpoint
https://kit.svelte.dev/docs/routing#page-page-server-js
https://kit.svelte.dev/docs/load
https://kit.svelte.dev/docs/load#making-fetch-requests
https://kit.svelte.dev/docs/routing#server

Why is my Mongodb aggregation pipeline update working in compass, but not working in my node driver

Problem:
I need to only update one document in a nested array of subdocuments. My previous query was updating all matching documents which is no good Example Below. So I decided to use aggregation so that I could add a limit stage so that I could only update one item, but I cannot get the update to happen through node and I am not even getting errors.
Old Query/Update:
This query updates all documents that match the shape of userId: "empty" I need it to only update the first match
const query = await db.collection('events').updateOne({
_id: new ObjectId(eventId),
createdBy: new ObjectId(createdBy),
"weights.weight": weight
},
{
$set: {
"weights.$.spotsAvailable.$[el2]": {
"name": applicantName,
"userId": new ObjectId(applicantId)
}
}
},
{
arrayFilters: [
{
"el2.userId": "empty"
}
]
})
I have tested the aggregation in the MongoDB compass aggregation builder and it works fine.
But in the actual node code no luck
I have tried:
Pluging in variables without the new ObjectId syntax
Plugin in variables with the new ObjectId syntax
Using the exact same hardcoded values that I got from copying the aggregation code from compass for the node driver
Example document
{
"_id": {
"$oid": "6398c34ca67dbe3286452f23"
},
"name": "test",
"createdBy": {
"$oid": "636c1778f1d09191074f9690"
},
"description": "testing",
"date": {
"$date": {
"$numberLong": "1645488000000"
}
},
"location": {
"type": "Point",
"coordinates": [
0,
0
]
},
"weights": [
{
"spotsAvailable": [
{
"name": "empty",
"userId": "empty"
},
{
"name": "empty",
"userId": "empty"
},
{
"name": "empty",
"userId": "empty"
}
],
"weight": 12
},
{
"spotsAvailable": [
{
"name": "empty",
"userId": "empty"
},
{
"name": "empty",
"userId": "empty"
}
],
"weight": 15
}
],
"eventApplicants": [
{
"userId": {
"$oid": "636c1778f1d09191074f9690"
},
"name": "Wayne Wrestler",
"weight": 15
}
]
}
Code:
const acceptOrRemoveApplicant = async (eventId: ObjectId, createdBy: ObjectId, applicantId: ObjectId, applicantName: string, boolean: boolean, weight: number): Promise<boolean | undefined> => {
console.log({ eventId, createdBy, applicantId, applicantName, boolean, weight })
if (boolean == true) {
try {
/*
* Requires the MongoDB Node.js Driver
* https://mongodb.github.io/node-mongodb-native
*/
const agg = [
{
'$match': {
'_id': new ObjectId('6398c34ca67dbe3286452f23'),
'createdBy': new ObjectId('636c1778f1d09191074f9690')
}
}, {
'$unwind': {
'path': '$weights'
}
}, {
'$unwind': {
'path': '$weights.spotsAvailable'
}
}, {
'$match': {
'weights.spotsAvailable.name': 'empty',
'weights.weight': 15
}
}, {
'$limit': 1
}, {
'$set': {
'weights.spotsAvailable.name': 'Wayen',
'weights.spotsAvailable.userId': '123456'
}
}
]
const client = await clientPromise;
const db = client.db();
const query = db.collection('events').aggregate(agg);
// const query = await db.collection('events').updateOne({
// _id: new ObjectId(eventId),
// createdBy: new ObjectId(createdBy),
// "weights.weight": weight
// },
// {
// $set: {
// "weights.$.spotsAvailable.$[el2]": {
// "name": applicantName,
// "userId": new ObjectId(applicantId)
// }
// }
// },
// {
// arrayFilters: [
// {
// "el2.userId": "empty"
// }
// ]
// })
if (query) {
console.log("we queried")
console.log({ query })
return true
} else {
throw new Error("User not added to event")
}
} catch (e) {
console.error(e);
}

Recursive function returns weird output?

So i have this problem where i need to fill a list with objects of children's ids,names and parents ids and names for further backend work.
When i select a child and I recursively fill the list it gives me this output
[
{
"_id": "6328354914a6c4002121c2c6",
"name": "sss21"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "ss21"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "s1"
},
{
"_id": "6328351214a6c4002121c2c5",
"name": "new"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "s1"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "ss21"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "sss21"
}
]
I use this function to fill the list
selectionOutput(node) {
const id = node._id;
const name = node.name;
if (node.parent !== null) {
this.selection.push({_id: id, name: name});
this.selectionOutput(node.parent);
}
this.selection.push({_id: id, name: name});
return this.selection;
}
The function expects a node with parent nodes which in this case is this one
{
"_id": "6328351214a6c4002121c2c5",
"name": "new"
}
the other 3 like "s1, ss21 and sss21" are its children.
How can i make the function return just
[
{
"_id": "6328351214a6c4002121c2c5",
"name": "new"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "s1"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "ss21"
},
{
"_id": "6328354914a6c4002121c2c6",
"name": "sss21"
}
]
I should probably add that my data structure looks like this:
{
"_id": "6328351214a6c4002121c2c5",
"name": "new"
"parent": null,
"children": {
"_id": "6328354914a6c4002121c2c6",
"name": "s1",
"parent": {"_id": "6328351214a6c4002121c2c5","name": "new"}
"children": {
"_id": "6328354914a6c4002121c2c6",
"name": "ss21",
"parent": {"_id": "6328354914a6c4002121c2c6","name": "s1"}
"children":{...} Hope you get the point
}
},...
}
Also my function is fed with and Object that is a child and it goes up a level from there. For example child3(parent: child2) -> child2(parent:child1) -> child1(parent: parent) -> parent. I want to map all the ids all the ancestors of the initial object including the id of the initial one.
Looking at your data structure you can try this approach:
data.reduce((accum, item) => {
const childs = [];
const getChilds = ({ _id, name, children}) => {
childs.push({ _id, name});
if (children) getChilds(children);
};
if (item.children) getChilds(item.children);
return [...accum, { _id: item._id, name: item.name, children: childs }];
}, [])
OR this one if you want all data at root level
data.reduce((accum, item) => {
const childs = [];
const getChilds = ({ _id, name, children}) => {
childs.push({ _id, name});
if (children) getChilds(children);
};
if (item.children) getChilds(item.children);
return [...accum, { _id: item._id, name: item.name }, ...childs];
}, [])
``
One push is all that the function needed. I moved the push before the if statement and it works fine now.
selectionOutput(node) {
const id = node._id;
const name = node.name;
this.selection.push({_id: id, name: name});
if (node.parent) {
this.selectionOutput(node.parent);
}
return this.selection;
}

delete an elemnt from an array inside another array with mongodb

hello everyone i have a document of materiels where each document has an array of articles and each article has an array of details here's my collection data:
{
"_id": "62f2404b42556d62e2939466",
"code": "120K",
"designation": "PIZZA",
"article": [
{
"etat": "Reçu",
"lot": "",
"marque": "Royal",
"fournisseur": "maatalah",
"dateachat": "2022-08-01T00:00:00.000Z",
"bc": null,
"bl": null,
"fc": null,
"quantite": 12,
"_id": "62f25d001a035d017369e1f8",
"detail": [
{
"serie": "12",
"ddp": "2023-01-01T00:00:00.000Z",
"_id": "62f3986fe462b8a173c7d220"
},
{
"serie": "13",
"ddp": "2023-03-01T00:00:00.000Z",
"_id": "62f39cc1862c1bf5bc40157a"
}
]
},
{
"etat": "Reçu",
"lot": "",
"marque": "margarita",
"fournisseur": "",
"dateachat": "2022-08-04T00:00:00.000Z",
"bc": null,
"bl": null,
"fc": null,
"quantite": 13,
"_id": "62f25d041a035d017369e1fb",
"detail": [
{
"serie": "12345",
"ddp": "2023-01-01T00:00:00.000Z",
"_id": "62f281158a159e976c7c68d5"
}
]
}
],
"qteglobal": 25,
"id": "62f2404b42556d62e2939466"
}
i want to remove an element from the detail array here my express js code:
const { id, idarticle, iddetail } = req.params;
const materiel = Materiel.findOneAndUpdate(
{ _id: id, "article._id": idarticle, "article.detail._id": iddetail },
{ $pull: { "article.$.detail": { _id: iddetail } } },
{ new: true }
);
there is no syntax error but the document it doesn't seem to be deleted.
Can anyone help me please ? thank you
Hello guys after trying some methods i end up with this solution:
const { id, idarticle, iddetail } = req.params;
await Materiel.findOneAndUpdate(
{
id,
"article._id": idarticle,
},
{
$pull: {
"article.$[].detail": {
_id: iddetail,
},
},
}
);

How to form an array of nested arrays in my specific case?

I have a specific usecase where I want to combine all objects from an array into one new array. So I have a form in my website where users while booking are adding participants. They can add as many participants as they want. I save them in database as JSON and now I want to form a array of all participants so that I can show them all in the table.
So I first fetch all transactions from a specific listing which I get as an Array of objects and then I loop through them all and only get the transaction.attributes.protectedData.questions which holds the participants of each transaction.
So my transactions object looks like:
[
{
"type":"transaction",
"attributes":{
"createdAt":"2021-06-24T08:50:26.911Z",
"protectedData":{
"questions":[
[
{
"question":"name",
"answer":"Mario North"
},
{
"question":"email",
"answer":"mario#gmail.com"
}
]
],
"ticketType":{
"name":"Main entry",
"quantity":1
}
}
}
},
{
"type":"transaction",
"attributes":{
"createdAt":"2021-06-24T08:48:57.646Z",
"protectedData":{
"questions":[
[
{
"question":"name",
"answer":"John Adkins"
},
{
"question":"email",
"answer":"john#gmail.com"
}
],
[
{
"question":"name",
"answer":"Thomas Smith"
},
{
"question":"email",
"answer":"thomas#gmail.com"
}
]
],
"ticketType":{
"name":"General entry",
"quantity":2
}
}
}
}
]
So I need to loop through each transaction, then loop through questions and each new array in questions array is a new participant. In each participant I need to save the createdAt and ticketType values from transaction property.
So my final array/object needs to look like this:
[
{
"createdAt":"2021-06-24T08:50:26.911Z",
"ticketType":"Main entry",
"name":"Mario North",
"email":"mario#gmail.com"
},
{
"createdAt":"2021-06-24T08:48:57.646Z",
"ticketType":"General entry",
"name":"John Adkins",
"email":"john#gmail.com"
},
{
"createdAt":"2021-06-24T08:48:57.646Z",
"ticketType":"General entry",
"name":"Thomas Smith",
"email":"thomas#gmail.com"
}
]
So I can get the list of participants with createdAt and ticketType added to each of them. But I don't know how can I get my question/answer to appear as my wanted object I posted upper. This is what I have:
export const denormalisedParticipantList = transactions => {
let participants = [];
transactions.map(transaction => {
const createdAt = transaction.attributes.createdAt;
const questions = transaction.attributes.protectedData?.questions;
const ticketType = transaction.attributes.protectedData?.ticketType?.name;
return questions.map(q => {
// Form new participant object
const participant = {
createdAt,
ticketType,
...Object.fromEntries(q.map(({ question, answer }) => [question, answer])),
};
// Push new participant
participants.push(participant);
});
});
return participants;
};
I've been trying to figure it out since last night and I can't make it work. Can anyone please help me figure out how can I make a final array from my transactions object, I would be extremly thankful.
Destructuring can be a powerful way of keeping track of what you are accessing in a complex object. Here with flatMap() to return a single flattened array and Object.fromEntries() to map the questions array to individual objects.
const input = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario#gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john#gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas#gmail.com" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]
const result = input.flatMap((
{
attributes: {
createdAt,
protectedData: {
questions,
ticketType: { name: ticketType } }
}
}
) => (
questions.map(p => ({
createdAt,
ticketType,
...Object.fromEntries(p.map(({ question, answer }) => [question, answer]))
}))
));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
var array = []
data.forEach((element) => {
var object = { created: null,ticketType: null,name: null,email: null }
object.created = element.attributes.createdAt;
object.ticketType = element.attributes.protectedData.ticketType.name;
var tmp_data = element.attributes.protectedData.questions;
tmp_data.forEach((tmp) => {
tmp.forEach((item) => {
if(item.question == "name"){
object.name = item.answer;
}else{
object.email = item.answer;
}
})
array.push(object);
})
})
try this :)
You can simply use reduce and map.
const data = [{ "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:50:26.911Z", "protectedData": { "questions": [[{ "question": "name", "answer": "Mario North" }, { "question": "email", "answer": "mario#gmail.com" }]], "ticketType": { "name": "Main entry", "quantity": 1 } } } }, { "type": "transaction", "attributes": { "createdAt": "2021-06-24T08:48:57.646Z", "protectedData": { "questions": [[{ "question": "name", "answer": "John Adkins" }, { "question": "email", "answer": "john#gmail.com" }], [{ "question": "name", "answer": "Thomas Smith" }, { "question": "email", "answer": "thomas#gmail.com" },{ "question": "gender", "answer": "male" }]], "ticketType": { "name": "General entry", "quantity": 2 } } } }]
const output = data.reduce(
(a, b) => [
...a,
...b.attributes.protectedData.questions.map(e => ({
createdAt: b.attributes.createdAt,
ticketType: b.attributes.protectedData.ticketType.name,
...e.reduce((acc, cur) => ({ ...acc, [cur.question]: cur.answer }), {}),
})),
],
[]
);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories