Exploring relationships in models: the ultimate guide to querying with @Ngrx/store

In my Angular 2 app utilizing Redux (with @ngrx/store), I have structured the store in the following way:

{

  modelA: {
    ids: [1, 2],
    entities: { 1: { name: "name modelA 1" },
                2: { name: "name modelA 2" }
              }
  },

  modelB: {
    ids: [5, 8],
    entities: { 5: { name: "name modelB 5" },
                8: { name: "name modelA 8" },
                9: { name: "name modelA 9" }
              }
  } 

}

Currently, I have two object types: modelA and modelB. This setup works fine at the moment. However, I am struggling to determine the optimal way to establish a relationship between them, such as representing that modelA has many modelB entries (one-to-many). Is it viable to structure it like this?

modelAmodelB: {
  entities: {
    1: [5],
    2: [8, 9]
  }
}

This is positioned at the root of the store, not nested within 'modelA'. While this approach might function, how would I then access the modelB entries from a specific modelA using @ngrx/store methods? For example, composing selector functions:

compose(getModelAEntities(number[]), getModelAModelBRelations(modelA_id: number), getModelAModelBState() );

I can retrieve this data using Observable.combineLatest

Observable
.combineLatest(
  this.store.select('contentContents'),
  this.store.select('contents'),
  (relations: any, contents: any) => {
    return relations.entities[1].map( id => {
      return contents.entities[id]
    })
  }
).subscribe( data => {
  console.log(data);
})

Yet, I'm uncertain if this method is correct: whenever I update the modelA entities object (e.g., adding a new one), the subscribe() is triggered, but the output remains unchanged because neither the modelA entity nor its associated modelB objects have altered.

Alternatively, I could perform the query like this

export const getModelAModelBs = (id) => {
  return state => 
    state.select( (s: any) => [s.modelAModelB.entities[id], s.modelB.entities])
    .distinctUntilChanged( (prev, next) => {

      const new_m = (next[0] || []).map( id => {
        return next[1][id];
      });

      const old_m = (next[0] || []).map( id => {
        return prev[1][id];
      });

      return prev[0] === next[0] && (JSON.stringify(new_m) === JSON.stringify(old_m))
    })
    .map( ([ids = [], modelBs]) => ids.map( id => modelBs[id]) );
};

//implementing the selector
this.store.let(getModelAModelBs(1)).subscribe( data => {
  console.log(data)
})

Still, I am unsure if this represents the optimal approach.

Answer №1

After encountering a similar challenge, I devised a solution involving the use of wrappers.

If you're facing a similar issue, consider checking out the ngrx-entity-relationship library at: https://www.npmjs.com/package/ngrx-entity-relationship

You can define selectors like this:

export const selectUserWithCompany = entityUser(
  entityUserCompany(),
);

Then, utilize it with the store in this way:

this.store.select(selectUserWithCompany, 'userId');

Resulting in:

{
  id: 'userId',
  companyId: 'companyId',
  company: {
    id: 'companyId',
    // ...,
  },
  // ...,
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a CSS animation that smoothly slides across the screen and unveils a hidden text/div once the animation is complete

I have been attempting to replicate the captivating CSS animations seen on a particular website: My goal is to imitate how the site: initially reveals a full-screen black div sliding away to the right progressively loads the black background (div ta ...

Vuejs v-for nested loops

After spending countless hours researching, I am determined to solve this problem. My objective is to create a questionnaire similar to a Google Form, with question groups, questions, and answers. The structure of my data looks like this: question_group: ...

Scrolling without limits - cylindrical webpage (CSS/JS)

Is it possible to create a page that infinitely scrolls from top to top without going straight back to the top, but instead showing the bottom content below after reaching it? Imagine being able to scroll up and see the bottom above the top like a 3D cylin ...

Angular version 11 fails to locate the lazy module

Here's a link to an application that is attempting to lazily load the BookModule using the following setup: const routes: Routes = [ { path: "", redirectTo: "/books", pathMatch: "full" }, { path: "books" ...

Having trouble with the HTML5 canvas for loop not rendering the initial object in the array?

Essentially, I'm attempting to iterate through each letter in a text string (specifically the text "marius"). However, there's an issue where the first letter is not being displayed. When the text is "marius", only "arius" is drawn. I've exh ...

Perform a Fetch API request for every element in a Jinja2 loop

I've hit a roadblock with my personal project involving making Fetch API calls to retrieve the audio source for a list of HTML audio tags. When I trigger the fetch call by clicking on a track, it always calls /play_track/1/ and adds the audio player ...

Is there a way to determine the quantity of items within a sortable div?

In my HTML document, there are multiple divs containing smaller divs that can be rearranged within each other. Upon loading the document, a random assortment of these smaller divs are added to #boxtop. Below is a snippet of my HTML code: <html> &l ...

Issues arising from a dysfunctional table inside a div container

Currently developing a quiz page and facing the challenge of integrating a scoreboard. Encountering an issue with placing the scoreboard in a table. As the table grows beyond 4 rows (which is expected), it extends endlessly. Attached below is a visual re ...

JavaScript can intelligently extract and categorize an array of objects based on their properties

In essence, I aim to develop a versatile function "organize" that can transform the following data structure: [ { name: 'band1', type: 'concert', subtype: 'rock' }, { name: 'band2', type: 'concert' ...

Even though I have properly set up the express.static() function and ensured that the path is correct, my initial app is still not serving the

Just like the title suggests, I am venturing into building my first node app and have come across an issue. Everything was working perfectly yesterday. However, when I booted up my PC today, I received the error message "Resource interpreted as Stylesheet ...

Console error due to misconfiguration of AngularJS checkbox option

My requirements are twofold: Only one of two boxes can be selected at a time. The name of the selected box must be captured. Although when I print out the list of checkbox objects they appear to be correct, checking in the console reveals otherwise. For ...

Exploring the Differences between HTML Values in HTML and jQuery

Can someone assist me with comparing HTML values to check for equality? I am looking to compare the values of two select elements in HTML and needing guidance on how to accomplish this. Specifically, I want to determine if the selected values from both s ...

What could be causing my Express API registration route to fail when attempting to POST?

Currently, I'm in the process of developing a compact authentication system for a practice project that I've undertaken. As part of this endeavor, I am sending POST requests via Postman to my Express server located at http://localhost:4000/api/re ...

Choosing multiple options from a list

I am working on a messaging app where users can compose and send messages to contacts. Currently, I am only able to send messages to one contact at a time. My goal is to enable users to select multiple contacts to create group messages. Since I am new to a ...

Deep-diff JavaScript functions are not permissible for use

In my AngularJS application, I am currently attempting to utilize a JavaScript package. To reference it in my index.html file, I added the following code: <script src="deep-diff-0.3.1.min.js"></script> Furthermore, in my controller, I am usin ...

I keep encountering the error message "SyntaxError: Cannot use import statement outside a module" even after including "type": "module" in the package.json file. How frustrating to still be faced with yet another error

Upon running the code snippet provided, an error message is displayed stating "SyntaxError: Cannot use import statement outside a module." Despite successfully installing node-fetch using npm install node-fetch What could be causing this issue? import fet ...

Displaying mongoose queries can be easily achieved by utilizing ng-repeat

I am trying to utilize Angular to display the array I receive from mongoose.find(). Below is my approach: Controller: requests:function(req,res){ corporate.find({request:false},function(err,corp){ if(corp){ console.log ...

Using a JMeter variable within JavaScript code: Tips and tricks

I am exploring ways to automate the process of logging in multiple users with different credentials on a web page. My solution involves using JMeter with Selenium to achieve this automation. To read the usernames and passwords from a CSV file, I need to pa ...

The Html is not having JavaScript executed before it

Within my header, there is a script that is making a call to a web API in order to populate a view model. The script is as follows: @using GigHub.Controllers @using GigHub.ViewModel @model GigHub.ViewModel.ProjectsViewModel @{ ViewBag.Title = "Projects"; ...

What is the best way to mimic a library using SinonJs?

I am dealing with a file named browser-launcher.ts import * as Browser from "@lib/browser"; class BrowserLauncher { launch(options) { browser = Browser(options); } } export const browserLauncher = new BrowserLauncher() W ...