How to create nested array in realm without key(React Native) - reactjs

{
"a": [
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
],
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
]
]
}
How to create the schema in the realm(React native) for this type of JSON object. I tried all possible ways but did not found any specific solution. Basically, it is a nested array where the second array does not have any specific key(I tried with key it works fine but I want to do it without adding key).

You can use something like:
const ParentSchema = {
name: "parent",
properties: {
key: "string",
values: "Value[]"
}
};
const ValueSchema = {
name: "Value",
embedded: true,
properties: {
_id: "string",
title: "string"
}
};
You can insert objects like:
realm.write(() => {
realm.create("Parent", { key: "a", values: [
{ _id: "57e55b64016c3551c025abc1", title: "Main Campus" },
{ _id: "5810e2e27064497f74ad4874", title: "Ahm Campus" }
]
});
});
Documentation: https://docs.mongodb.com/realm/node/data-model

As of now there is no way to insert direct value in Realm database without key so for now we need to modify data and then we can store in following schema.
const ParentSchema = {
name: "parent",
properties: {
a: "level[]"
}
};
const level = {
name: 'level',
properties: {
level: 'sites[]'
}
}
const sites = {
name: 'sites',
properties: {
sites: 'site[]'
}
}
const site = {
name: 'site',
properties: {
title: 'string?',
_id: 'string?',
version: 'int?',
}
}
Data modification need to done like following.
var a = {
level: []
}
data.a.map((Site, index) => {
const sites = []
Site.map((s) => { sites.push(s)})
a.level.push({sites})
})

Related

Retrieving related elements from MongoDB

I have the following data in MongoDB. Based alone on an id that I have available how can I retrieve all other entries where the player matches the player for my current id.
For example : find who the player for id 12 is, search all other entries that match that player name and return a list of all of them.
[
{_id: '62ecdf342f1193134043964c', id: '12', player: 'David Beckham', team: 'Manchester United'},
{_id: '62ecdf342f1193134043965c', id: '17', player: 'Cristiano Rolando', team: 'Manchester United'},
{_id: '62ecdf342f1193134043966c', id: '22', player: 'Cristiano Rolando', team: 'Juventus'},
{_id: '62ecdf342f1193134043967c', id: '42', player: 'David Beckham', team: 'Real Madrid'},
]
This is the code that I'm using to retrieve the one single entry that matches a specific id and then I'd also like to get the related entries.
export async function getStaticProps({ params }) {
const { db } = await connectToDatabase();
const jerseyA = await db
.collection("Jerseys")
.find({ id: params.jersey })
.sort()
.toArray();
const jersey = JSON.parse(JSON.stringify(jerseyA))[0];
return { props: { jersey } };
}
Now that you know the name, do another fetch like .find({player: jersey.player})
I'm not sure of the output format you want, but here's one way to return all documents that match the "player" name of the given "id".
db.Jerseys.aggregate([
{
"$match": {
// your id goes here
"id": "17"
}
},
{
"$lookup": {
"from": "Jerseys",
"localField": "player",
"foreignField": "player",
"as": "docs"
}
},
{"$unwind": "$docs"},
{"$replaceWith": "$docs"}
])
Example output:
[
{
"_id": "62ecdf342f1193134043965c",
"id": "17",
"player": "Cristiano Rolando",
"team": "Manchester United"
},
{
"_id": "62ecdf342f1193134043966c",
"id": "22",
"player": "Cristiano Rolando",
"team": "Juventus"
}
]
Try it on mongoplayground.net.
Just an addition to #rickhg12hs solution, to ignore the first record. You can use the following query to ignore the first record (where the id also matched) and the others.
db.Jerseys.aggregate([
{
"$match": {
"id": "12"
}
},
{
"$lookup": {
"from": "Jerseys",
"localField": "player",
"foreignField": "player",
"as": "docs"
}
},
{
"$unwind": "$docs"
},
{
"$replaceWith": "$docs"
},
{
"$match": {
"id": {
"$not": {
"$eq": "12"
}
}
}
}
])
A possible javascript translation of it, should be,
export async function getStaticProps({ params }) {
const { db } = await connectToDatabase();
const { jersey: id } = params;
const jerseyA = await db
.collection("Jerseys")
.aggregate([
{
"$match": {
id
}
},
{
"$lookup": {
"from": "Jerseys",
"localField": "player",
"foreignField": "player",
"as": "docs"
}
},
{
"$unwind": "$docs"
},
{
"$replaceWith": "$docs"
},
{
"$match": {
"id": {
"$not": {
"$eq": id
}
}
}
}
]).toArray();
const jersey = JSON.parse(JSON.stringify(jerseyA))[0];
return { props: { jersey } };
}

how to take array values as key value pair in angular

I'm new to api. I have two arrays let it be A and B, both A and B contains json response,
Array A has the following data.
{
"servers": [
{
"links": [
{
"href": ,
"rel": "self"
},
{
"href": ",
"rel": "bookmark"
}
],
"rel": "bookmark"
}
]
},
"OS-EXte": "active",
"OS-TR:instance_name": "instance-000",
"OS-SRV-Uched_at": "20200",
"flavor": {
"id": "fe183ca7-610f-4db4-934",
"links": [
{
"href":
"rel": "bookmark"
}
]
},
and so on and array B has
{
"flavors": [
{
"name": "ti",
"links": [
{
"href": "",
"rel": "self"
},
],
"ram": 8192,
"OS-FLV-DISABLEse,
},
{
I need to take all the flavor id from array A which is matching in array B.
let servers = [{
flavor: {
id: "1",
links: [{
rel: "bookmark"
}]
}
}, {
flavor: {
id: "2",
links: [{
rel: "any"
}]
}
}]
let flavors = [{
name: "ti",
ram: 8192,
id: "1"
}, {
name: "ti",
ram: 8192,
id: "2"
}, {
name: "ti",
ram: 8192,
id: "3"
}]
let serverFlavors = servers.map(s => s.flavor.id)
let newArray = flavors.filter(f => serverFlavors.includes(f.id))
console.log(newArray)
If your data is json, you can parse the json and then do the above.
parse JSON like
JSON.parse(<strigifiedJSON>)
I think you can first map all the flavor Id from Array A to the new Array.
And then filer Array B from mapped Flavor Array .
Assuming Servers is Array A -
let serverFlavor = servers.map(row => { row.flavor.id});
let filteredRam = flavors.filter(row => serverFlavor.find((a) => a == row.id));
Then you can use reduce function on filteredRam Array .

React - setState with certain index

I've been stuck for whole day and please help me to fix it.
I have a json data which like this :
[
{
"menu": "menu_1",
"icon": "icon_1",
"detail": {
"name": "name_1",
"phone": "phone_1"
}
},
{
"menu": "menu_2",
"icon": "icon_2",
"detail": {
"name": "name_2",
"phone": "phone_2"
}
},
{
"menu": "menu_3",
"icon": "icon_3",
"detail": {
"name": "name_3",
"phone": "phone_3"
}
}
]
I put them into the "data" state and My goal is I wanna change the "detail" state with certain index ( ex: state "data" with index 1 change the "detail" data )
Currently my code is :
this.setState({
data: {
...this.state.data,
detail:{
this.state.data[1].detail:{
"name": "billy",
"phone": "893823839"
}
}
}
})
That setState is clearly wanna change the state with certain index but fail..
How do I supposed to do?
I guess this is what you're looking for, we could replace an element inside an array using splice :
const index = 1;
this.setState({
data: [...this.state.data].splice(index, 1, {
...this.state.data[index],
details: { name: "billy", phone: "893823839" },
}),
});
Update: we could use slice also to make an immutable update with index :
this.setState({
data: [
...this.state.data.slice(0, index),
{
...this.state.data[index],
details: { name: "billy", phone: "893823839" },
},
...this.state.data.slice(index + 1, this.state.data.length),
],
});
could you try it ?
this is an example that i tested using splice:
const items = [{ id: 1 }, { id: 2 }, { id: 3 }];
const indexToBeModified = 1; // { id: 2 } ==> { foo: "foo", id: 2 }
items.splice(indexToBeModified, 1, { ...items[indexToBeModified], foo: "foo" });
console.log("items", items);
Here is a little modified example. It uses prevState to prevent any unwanted changes that may happen when directly interacting with this.state.
import React, { Component } from "react";
export default class App extends Component {
constructor() {
super();
this.state = {
data: [
{
menu: "menu_1",
icon: "icon_1",
detail: {
name: "name_1",
phone: "phone_1"
}
},
{
menu: "menu_2",
icon: "icon_2",
detail: {
name: "name_2",
phone: "phone_2"
}
},
{
menu: "menu_3",
icon: "icon_3",
detail: {
name: "name_3",
phone: "phone_3"
}
}
]
};
this.modifyData = this.modifyData.bind(this);
}
modifyData(index) {
this.setState((prevState) => {
prevState.data[index].detail={
name: "billy",
phone: "893823839"
};
return {
data: [prevState.data]
};
},()=>{console.log(this.state.data)});
}
render() {
return (
<button onClick={() => this.modifyData(0)}>Click to modify data</button>
);
}
}
Here is a code sandbox reference.

React setState - Add array to nested object with multiple arrays

I'm currently working on a new application in React. This is the first time I'm creating something in React. The application will display our own promotions.
My initial state is as follows:
{
"promotion": {
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [
{
"startDateTimeStamp": 1510558814960,
"endDateTimeStamp": 1510558814960,
"variants": [
{
"title": "",
"text": "",
"image": ""
}
]
}
]
}
}
This is created from my defaultPromotion constant. This constant is stored in a separate file, which I call api.js
export const defaultPromotion = {
name: '',
campaign: '',
url: 'https://',
position: 0,
periods: [
{
startDateTimeStamp: Date.now(),
endDateTimeStamp: Date.now(),
variants: [
{
title: '',
text: '',
image: '',
},
]
},
]
}
In my createPromotion component it's created as followed
let promotionState = api.promotions.defaultPromotion;
this.state = {
promotion: promotionState
};
I can add a new period with the following:
addPromotion() {
let promotion = this.state.promotion;
promotion.periods.push( api.promotions.defaultPromotion.periods[0] );
this.forceUpdate();
}
After that, a new period is added as expected. Suggestions to do this with setState() are very welcome! So, my new state is now:
{
"promotion": {
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [
{
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [
{
"title": "",
"text": "",
"image": ""
}
]
},
{
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [
{
"title": "",
"text": "",
"image": ""
}
]
}
]
}
}
Now, I want to add a new variant for this promotion period, this is where I'm stuck for 2 days now.
I'm adding a new period as follows:
addVariant( periodKey ) {
const promotion = this.state.promotion;
promotion.periods[periodKey].variants.push(api.promotions.defaultPromotion.periods[0].variants[0]);
this.setState({ promotion: promotion });
}
periodKey is here "1", so, I'm expecting that there will be added a new variant for periods[1], but, it's added to both periods. State is now as follows:
{
"promotion": {
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [
{
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [
{
"title": "",
"text": "",
"image": ""
},
{
"title": "",
"text": "",
"image": ""
}
]
},
{
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [
{
"title": "",
"text": "",
"image": ""
},
{
"title": "",
"text": "",
"image": ""
}
]
}
]
}
}
Can someone explain me why this is happening and how I can add a new variant the right way?
Many, many thanks in advance!
UPDATE 1
Based on the answers from bennygenel and Patrick Hübl-Neschkudla, my implementation is now as follows:
Setting the initial state:
constructor(props) {
super(props);
let promotionState = api.promotions.defaultPromotion;
this.state = { ...promotionState };
}
Method:
addVariant( periodKey ) {
this.setState((prevState) => {
const { periods } = prevState;
periods[periodKey].variants.push(
Object.assign({}, { ...periods[periodKey].variants, api.promotions.defaultPromotion.periods[0].variants[0]})
);
return { periods };
});
}
But this still is setting the new variant in all the periods. I've also tried the exact code from Benny, but with the same results. The method is called as
this.props.addVariant( this.props.periodKey );
Even when I call it as:
this.props.addVariant(2);
The same behaviour is happening.
UPDATE 2
I now have rewritten everything to redux, this is so I have access to my promotion in every component the easy way, instead off passing them through certain components. Based on the answer of #mersocarlin, I now have the following reducer cases:
Add period
case PROMOTION_ADD_PERIOD:
const { periods } = { ...state };
periods.push(api.promotions.defaultPromotion.periods[0]);
state = {
...state,
periods: periods
};
break;
Add a period variant
case PROMOTION_ADD_PERIOD_VARIANT :
state = {
...state,
periods: [
...state.periods[action.payload.period],
{
variants: [
...state.periods[action.payload.period].variants,
api.promotions.defaultPromotion.periods[0].variants[0]
]
}
]
};
break;
The following case:
Add a new variant, works, state:
{
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [
{
"startDateTimeStamp": 1510599968588,
"endDateTimeStamp": 1510599968588,
"variants": [
{
"title": "",
"text": "",
"image": ""
}
]
},
{
"startDateTimeStamp": 1510599968594,
"endDateTimeStamp": 1510599968594,
"variants": [
{
"title": "",
"text": "",
"image": ""
}
]
}
]
}
After that, adding a new variant, kinda works, well, the variant is added, but I'm losing my 2nd period. State:
{
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [
{
"variants": [
{
"title": "",
"text": "",
"image": ""
},
{
"title": "",
"text": "",
"image": ""
}
]
}
]
}
I think this is a small thing I'm not see'ing. Does someone have the solution for the "PROMOTION_ADD_PERIOD_VARIANT" case?
Update 3
Changed the "PROMOTION_ADD_PERIOD" case as follows:
case PROMOTION_ADD_PERIOD:
state = {
...state,
periods: [
...state.periods,
initialState.periods[0]
]
};
break;
Update 4
Finaly found the solution. See the final code for PROMOTION_ADD_PERIOD_VARIANT below:
state = {
...state,
periods: [
...state.periods.map((item, index) => {
if ( index !== action.payload.period ) {
return item;
}
return {
...item,
variants: [
...item.variants,
initialState.periods[0].variants[0]
]
}
})
]
};
Thank you all so much for your help!!
Rather destruct your state object and avoid mutating it directly. This also happens to be a bad pattern.
Whenever you need to add a new item to the array:
const state = {
arrayProp: [{ prop1: 'prop1', prop2: 'prop2' }]
}
const newItem = {
prop1: 'value1',
prop2: 'value2',
}
const newState = {
...state,
arrayProp: [
...state.arrayProp,
newItem,
]
}
console.log('newState', newState)
Same applies for nested properties within your state:
Redux also uses this very same approach
const state = {
objectProp: {
arrayPropWithinArray: [
{ id: '0', otherProp: 123, yetAnotherProp: 'test' },
{ id: '1', otherProp: 0, yetAnotherProp: '' }
]
}
}
const { objectProp } = state
const index = objectProp.arrayPropWithinArray.findIndex(obj => obj.id === '1')
const newSubItem = {
otherProp: 1,
yetAnotherProp: '2',
}
const newState = {
...state,
objectProp: {
...objectProp,
arrayPropWithinArray: [
...objectProp.arrayPropWithinArray.slice(0, index),
{
...objectProp.arrayPropWithinArray[index],
...newSubItem,
},
...objectProp.arrayPropWithinArray.slice(index + 1),
]
}
}
console.log('newState', newState)
Your specific case (as described in your comment)
const periodKey = '2' // your periodKey var. Get it from the right place, it can be your action for example
const index = state.periods.findIndex(period => period.id === periodKey) // find which index has to be updated
state = {
...state, // propagates current state
periods: [
...state.periods.slice(0, index), // propagates everything before index
{
...state.periods[index],
variants: [
...state.periods[index].variants,
api.promotions.defaultPromotion.periods[0].variants[0],
],
},
...state.periods.slice(0, index + 1) // propagates everything after index
]
}
So, what's happening here is that you have an array with two references to the same object.
Imagine it like this:
myArray[0] = reference to defaultPromotion
myArray[1] = reference to defaultPromotion
That's actually a wonderful example of why immutability concepts got so much attention in the past few years :)
What you'd want to do here is instead of adding the defaultPromotion object to the promotions array, you create a new object with the same props as this object and add it. It would look something like this (depending on your ES version etc.)
promotion.periods.push(
Object.assign({}, api.promotions.defaultPromotion.periods[0])
);
This way, you're creating a new object and pass this to the array instead of a reference to the already existing one.
First suggestion, if you are going to have only one promotion object in your state and not an array, lose the promotion level. this will reduce the complexity of your state. You can use spread syntax to easily set your initial state.
Example
let promotionState = api.promotions.defaultPromotion;
this.state = { ...promotionState };
Above code would end up creating a state like below;
{
"name": "",
"campaign": "",
"url": "https://",
"position": 0,
"periods": [{
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [{
"title": "",
"text": "",
"image": ""
}]
}, {
"startDateTimeStamp": 1510559984421,
"endDateTimeStamp": 1510559984421,
"variants": [{
"title": "",
"text": "",
"image": ""
}]
}]
}
Another suggestion I can make is to use functional setState to reduce possibility to mutate.
Example
addPromotion() {
this.setState((prevState) => {
const { periods } = prevState;
periods.push(api.promotions.defaultPromotion.periods[0]);
return { periods };
});
}
addVariant( periodKey ) {
this.setState((prevState) => {
const { periods } = prevState;
periods[periodKey].variants.push(api.promotions.defaultPromotion.periods[0].variants[0]);
return { periods };
});
}

Nodejs Mongoose select a entire document but only with selected items in a property array

I'm new to nodejs and currently i'm developing a Web API using nodejs, express and mongoose. Can anyone help me on following mongoose query.
var EventSchema = new Schema({
event_title: {
type: String,
required: true
},
service_order: [{
_id:{
type: String
},
service : {
type: Schema.Types.ObjectId,
ref: "Service"
}
}]
});
I want to select a entire Event document but only with selected service_order items in that array
ex :-
this is a entire Event document
{
_id: "sample_id",
name: 'some name',
"service_order": [
{
"_id": "1"
"service": {
"_id": "59c005524d9c141fe0d95f15"
},
{
"_id": "2"
"service": {
"_id": "59c005524d9c141fe0d95f18"
},
{
"_id": "3"
"service": {
"_id": "59c005524d9c141fe0d95f18"
},
{
"_id": "4"
"service": {
"_id": "59c005524d9c141fe0d95f18"
}
],
}
But I want to execute a single mongoose query which can give this as the output
{
_id: "sample_id",
name: 'some name',
"service_order": [
{
"_id": "1"
"service": {
"_id": "59c005524d9c141fe0d95f15"
},
{
"_id": "2"
"service": {
"_id": "59c005524d9c141fe0d95f18"
}
],
}
Initially I know the Event id ("sample_id") and the ids of service_orders that i want to select ( ["1","2"] ).
You can use mongodb aggregate to achieve that
don't forget to replace sample_id and ["1" , "2"] with your dynamic data
Check the code below:
db.event.aggregate([
{
$match: { _id: "sample_id" }
},
{
$unwind: { path: "$service_order" }
},
{
$match : { 'service_order._id' : { $in : [ "1" , "2"]} }
},
{
$group : {
_id: { _id: "$_id", "name": "$name"},
service_order: { $addToSet: "$service_order" },
}
},
{
$project : {
_id : "$_id._id",
name : "$_id.name",
service_order : 1
}
}
])

Resources