How to object property parse to nested array array using javascript? - javascript

It receives data from the request body in the following format. Properly I have to insert it into the database but the format is not correct.
{
name: '123',
description: 'Dev',
"item_variants[0]['name']": '23434',
"item_variants[0]['quantity']": '12334',
"item_variants[0]['unit_price']": '123123',
}
And how to transform the following format? Everyone's answers help me some ideas. Thank you
{
name: '123',
description: 'Dev',
item_variants: [
{
name: '23434',
quantity: '23434',
unit_price: '23434',
}
]
}

In express, after getting this form body you have to store this response in any variable and reformate this response after formatting you can save it into the database.
try {
let inputs = req.body;
inputs = {
name: inputs.name,
description: inputs.description,
item_variants: [
{
name: item_variants[0].name,
quantity: item_variants[0].quantity,
unit_price: item_variants[0].unit_price,
},
],
};
// NOW you can save this formatted version into the database
const result = await Product.save(inputs);
} catch (e) {
console.log(e);
}
In item_variants name, quantity, unit_price you might change digging and getting value.

Related

mongodb convert data to string. how to fix?

I want to get data from my database to work with variables.
Here is my database query:
db.progress.find({username:socket},function(err,res){
what do I get information on:
[ { _id: 61e180b54e0eea1454f8e5e6,
username: 'user',
exp: 0,
fraction: 'undf'} ]
if i send a request
db.progress.find({username:socket},{exp:1},function(err,res){
then in return I will get
[ { _id: 61e180b54e0eea1454f8e5e6, exp: 0 } ]
how do i extract only 0 from the received data. I would like to do something like this.
var findprogress = function(socket,cb){
db.progress.find({username:socket},function(err,res){
cb(res.exp,res.fraction)
})
}
findprogress(socket,function(cb){
console.log(cb.exp)//0
console.log(cb.fraction)//undf
})
but I don't know how to implement it correctly.
I recommend aggregate in this case so you can more easily manipulate your projected data. For example:
db.progress.aggregate([
{ $match: { username: socket } },
{ $project: { _id: 0, exp: 1 } }
])
This way you directly tell the query to not include the objectId, which is typically included by default.
find returns an array, so you will need to select the array element before accessing the field:
var findprogress = function(socket,cb){
db.progress.find({username:socket},function(err,res){
cb(res[0].exp,res[0].fraction)
})
}
Try to give 0 to _id:
db.progress.find({username:socket},{exp:1 , _id:0},function(err,res){

Is there a way to update an object in an array of a document by query in Mongoose?

I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.

How to get an object from a MongoDB nested array

I have a MongoDB collection for storing chat objects with messages embedded as a nested array. The entire collection looks like this:
chats = [
{
_id: 0,
messages: [
{
_id: 0,
text: 'First message'
},
{
_id: 1,
text: 'Second message'
}
]
},
{
_id: 1,
messages: []
}
]
I would like to update a single message and return it to the user. I can update the message like this (in Node):
const chat = chats.findOneAndUpdate({
_id: ObjectId(chatID),
"messages._id": ObjectId(messageID)
}, {
$set: {
"messages.$.text": newText
}
});
The issue is that this query updates a message and returns a chat object, meaning that I have to look for an updated message in my code again. (i.e. chat.messages.find(message => message._id === messageID)).
Is there a way to get a message object from MongoDB directly? It would also be nice to do the update in the same query.
EDIT: I am using Node with mongodb.
Thank you!
Since MongoDB methods findOneAndUpdate, findAndModify do not allow to get the updated document from array field,
projection will return updated sub document of array using positional $ after array field name
returnNewDocument: true will return updated(new) document but this will return whole document object
The problem is, MongoDB cannot allowing to use a positional projection and return the new document together
For temporary solution
try using projection, this will return original document from array field using $ positional,
const chat = chats.findOneAndUpdate(
{
_id: ObjectId(chatID),
"messages._id": ObjectId(messageID)
},
{ $set: { "messages.$.text": newText } },
{
projection: { "messages.$": 1 }
}
);
Result:
{
"_id" : 0.0,
"messages" : [
{
"_id" : 0.0,
"text" : "Original Message"
}
]
}
To get an updated document, a new query could be made like this:
const message = chats.findOne({
_id: ObjectId(chatID),
"messages._id": ObjectId(messageID)
}, {
projection: {'messages.$': 1},
}).messages[0];
Result:
{
"_id": 0.0,
"text": "New message",
}

Normalizr - is it a way to generate IDs for non-ids entity model?

I'm using normalizr util to process API response based on non-ids model. As I know, typically normalizr works with ids model, but maybe there is a some way to generate ids "on the go"?
My API response example:
```
// input data:
const inputData = {
doctors: [
{
name: Jon,
post: chief
},
{
name: Marta,
post: nurse
},
//....
}
// expected output data:
const outputData = {
entities: {
nameCards : {
uniqueID_0: { id: uniqueID_0, name: Jon, post: uniqueID_3 },
uniqueID_1: { id: uniqueID_1, name: Marta, post: uniqueID_4 }
},
positions: {
uniqueID_3: { id: uniqueID_3, post: chief },
uniqueID_4: { id: uniqueID_4, post: nurse }
}
},
result: uniqueID_0
}
```
P.S.
I heard from someone about generating IDs "by the hood" in normalizr for such cases as my, but I did found such solution.
As mentioned in this issue:
Normalizr is never going to be able to generate unique IDs for you. We
don't do any memoization or anything internally, as that would be
unnecessary for most people.
Your working solution is okay, but will fail if you receive one of
these entities again later from another API endpoint.
My recommendation would be to find something that's constant and
unique on your entities and use that as something to generate unique
IDs from.
And then, as mentioned in the docs, you need to set idAttribute to replace 'id' with another key:
const data = { id_str: '123', url: 'https://twitter.com', user: { id_str: '456', name: 'Jimmy' } };
const user = new schema.Entity('users', {}, { idAttribute: 'id_str' });
const tweet = new schema.Entity('tweets', { user: user }, {
idAttribute: 'id_str',
// Apply everything from entityB over entityA, except for "favorites"
mergeStrategy: (entityA, entityB) => ({
...entityA,
...entityB,
favorites: entityA.favorites
}),
// Remove the URL field from the entity
processStrategy: (entity) => omit(entity, 'url')
});
const normalizedData = normalize(data, tweet);
EDIT
You can always provide unique id's using external lib or by hand:
inputData.doctors = inputData.doctors.map((doc, idx) => ({
...doc,
id: `doctor_${idx}`
}))
Have a processStrategy which is basically a function and in that function assign your id's there, ie. value.id = uuid(). Visit the link below to see an example https://github.com/paularmstrong/normalizr/issues/256

GraphQL mutation that accepts an array of dynamic size and common scalar types in one request

I need to be able to create a user and add it's favourite movies (An array of objects with a reference to the Movies collection and his personal rating for each movie) in a single request.
Something that could look like this (pseudocode)
var exSchema = `
type Mutation {
addUser(
name: String!
favMovies: [{ movie: String! #ref to movies coll
personal_rating: Int! # this is different for every movie
}]
) : User
}
...
`
What is the graphql way of doing this in a single request? I know I can achieve the result with multiple mutations/requests but I would like to do it in a single one.
You can pass an array like this
var MovieSchema = `
type Movie {
name: String
}
input MovieInput {
name: String
}
mutation {
addMovies(movies: [MovieInput]): [Movie]
}
`
Then in your mutation, you can pass an array like
mutation {
addMovies(movies: [{name: 'name1'}, {name: 'name2'}]) {
name
}
}
Haven't tested the code but you get the idea
I came up with this simple solution - NO JSON used. Only one input is used. Hope it will help someone else.
I had to add to this type:
type Option {
id: ID!
status: String!
products: [Product!]!
}
We can add to mutation type and add input as follows:
type Mutation {
createOption(data: [createProductInput!]!): Option!
// other mutation definitions
}
input createProductInput {
id: ID!
name: String!
price: Float!
producer: ID!
status: String
}
Then following resolver could be used:
const resolvers = {
Mutation: {
createOption(parent, args, ctx, info) {
const status = args.data[0].status;
// Below code removes 'status' from all array items not to pollute DB.
// if you query for 'status' after adding option 'null' will be shown.
// But 'status': null should not be added to DB. See result of log below.
args.data.forEach((item) => {
delete item.status
});
console.log('args.data - ', args.data);
const option = {
id: uuidv4(),
status: status, // or if using babel status,
products: args.data
}
options.push(option)
return option
},
// other mutation resolvers
}
Now you can use this to add an option (STATUS is taken from first item in the array - it is nullable):
mutation{
createOption(data:
[{
id: "prodB",
name: "componentB",
price: 20,
producer: "e4",
status: "CANCELLED"
},
{
id: "prodD",
name: "componentD",
price: 15,
producer: "e5"
}
]
) {
id
status
products{
name
price
}
}
}
Produces:
{
"data": {
"createOption": {
"id": "d12ef60f-21a8-41f3-825d-5762630acdb4",
"status": "CANCELLED",
"products": [
{
"name": "componentB",
"price": 20,
},
{
"name": "componentD",
"price": 15,
}
]
}
}
}
No need to say that to get above result you need to add:
type Query {
products(query: String): [Product!]!
// others
}
type Product {
id: ID!
name: String!
price: Float!
producer: Company!
status: String
}
I know it is not the best way, but I did not find a way of doing it in documentation.
I ended up manually parsing the correct schema, since JavaScript Arrays and JSON.stringify strings were not accepted as graphQL schema format.
const id = 5;
const title = 'Title test';
let formattedAttachments = '';
attachments.map(attachment => {
formattedAttachments += `{ id: ${attachment.id}, short_id: "${attachment.shortid}" }`;
// { id: 1, short_id: "abcxyz" }{ id: 2, short_id: "bcdqrs" }
});
// Query
const query = `
mutation {
addChallengeReply(
challengeId: ${id},
title: "${title}",
attachments: [${formattedAttachments}]
) {
id
title
description
}
}
`;
What i understand by your requirement is that if you have the following code
const user = {
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
{name:"maths"},
{name:"science"}
]
};
const query = `mutation {
createUser(user:${user}) {
name
}
}`
you must be getting something like
"mutation {
createUser(user:[object Object]) {
name
}
}"
instead of the expected
"mutation {
createUser(user:{
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
{name: "maths" } ,
{name: "science" }
]
}) {
name
}
}"
If this is what you wanted to achieve, then gqlast is a nice tag function which you can use to get the expected result
Simply grab the js file from here and use it as:
const user = {
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
{name:"maths"},
{name:"science"}
]
};
const query = gqlast`mutation {
createUser(user:${user}) {
name
}
}`
The result stored in the variable query will be :
"mutation {
createUser(user:{
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
{name: "maths" } ,
{name: "science" }
]
}) {
name
}
}"
Pass them as JSON strings. That's what I do.
For those of you who don't need to pass in an array for one request, and are open to the idea of making a request for every mutation. (I am using Vue3, compisition Api, but React and Angular developers still can understand this).
You cannot for loop the mutation like this:
function createProject() {
for (let i = 0; i < state.arrOfItems.length; i++) {
const { mutate: addImplementation } = useMutation(
post_dataToServer,
() => ({
variables: {
implementation_type_id: state.arrOfItems[i],
sow_id: state.newSowId,
},
})
);
addImplementation();
}
}
this will give you an error, because the mutation must be in the setup().
(here is the error you will recieve: https://github.com/vuejs/vue-apollo/issues/888)
Instead create a child component, and map the array in the parent.
in Parent.vue
<div v-for="(card, id) in state.arrOfItems">
<ChildComponent
:id="id"
:card="card"
/>
</div>
in ChildComponent.vue
recieve props and:
const { mutate: addImplementation } = useMutation(
post_dataToServer,
() => ({
variables: {
implementation_id: props.arrOfItems,
id: props.id,
},
})
);

Categories

Resources