I would like to know how to group documents according to a condition, and publish to the client.
Suppose I have the following documents:
[
{ name: 'John', createdAt: some_date_value_1 },
{ name: 'Jane', createdAt: some_date_value_2 },
{ name: 'Bob', createdAt: some_date_value_1 },
{ name: 'Jenny', createdAt: some_date_value_2 }
]
What can I do to publish a result like this?
{
some_date_value_1: [
{ name: 'John', createdAt: some_date_value_1 },
{ name: 'Bob', createdAt: some_date_value_1 }
],
some_date_value_2: [
{ name: 'Jane', createdAt: some_date_value_2 },
{ name: 'Jenny', createdAt: some_date_value_2 }
]
}
Any suggestions?
It depends of you want to do it on client or server.
First, the obvious solution: if you have no specific reason to store them with the first structure, store them directly using the second.
Second, another easy solution is to make in client. Here is a non tested code using undercore (bundled with meteor):
var yourCollection = CollectionName.find();
var yourCollectionByDate = _.groupBy(yourCollection , 'createdAt');
Third, you could still do it on server but either you will loose the reactivity of your collection (using for instance Collection.aggregate with a package) or have to transform and observe all changes afterwards (it would be a little overkill. However have a look here if you want more info)
A quick side note too: unless you want the users names to be unique, you should rely on mongo unique id (_.id) rather than on a name you set. That way, you are sure that you link to the right item (no duplicate).
Related
For example, I have
[
{ name: "John" },
{ name: "Mike" },
{ name: "Homer" },
{ name: "Bart" },
{ name: "Dmitry" },
{ name: "Dan" }
]
How will I choose many objects with mongoose, if I use .limit(2) I will get [{ name: "John" }, { name: "Mike" }], I need to choose [{ name: "Bart" }, { name: "Dmitry" }]. In default JS this method looks like .slice(3,5). How will I do it with mongoose?
You can try something like this:
Model.find({name: {$in: ["Bart", "Dmitry"]}});
You can achieve this in mongodb by using skip(3).limit(2).
In Mongoose you can achieve this with myModel.find({}, 'name', {skip: 3, limit: 2}), you just have to insert values of skip and limit you want in third parameter of find.
Here's documentation with an example of skip and here's a link to a more popular answer of similar problem.
Edit: Note that this is a short-sighted solution, you should use something else for large or changing database.
Background
Here's part of my User model:
const Group = require("./Group")
...
groups: {
type: [{ type: Schema.ObjectId, ref: Group }],
default: [],
},
And here's my Group model:
module.exports = mongoose.model(
"Group",
new Schema(
{
name: {
type: String,
required: true,
unique: true,
},
/**
* Array of User ObjectIDs that have owner rights on this group
*/
owners: {
type: [{ type: Schema.ObjectId, ref: User }],
default: [],
},
},
{
timestamps: true,
}
)
)
The Code
Here's the code I'm running to try and populate:
const user = await (await User.findOne({ _id: ... })).execPopulate("Group")
console.log(user.groups)
My console.log is outputting an array of object IDs, when I'd like it to output an actual Group document.
Attempted solutions
I've tried changing my ref to be using the string ("Group"), I've tried arranging my query differently, etc. I'm not sure how I'd go about doing this.
Apologies in advance if this is a duplicate, I've done my best to search but can't really find a solution that works for me.
Specifically, what do I need help with?
I'm trying to create a 'link' between a user model and a group model. In my console.log, I expect it to output a Group document; but it outputs an object ID (which is how it's stored raw in the database, meaning that Mongoose isn't transforming it correctly)
When you change execPopulate to populate like:
async function findUserAndPopulate(userId){
const response = await User.findOne({
_id: userId,
}).populate('groups')
console.log("response",response)
}
You got:
{
groups: [
{
owners: [Array],
_id: 5ecc637916a2223f15581ec7,
name: 'Crazy',
createdAt: 2020-05-26T00:31:53.379Z,
updatedAt: 2020-05-26T00:31:53.379Z,
__v: 0
}
],
_id: 5ecc6206820d583b99b6b595,
fullname: 'James R',
createdAt: 2020-05-26T00:25:42.948Z,
updatedAt: 2020-05-26T00:36:12.186Z,
__v: 1
}
So you can access the user.groups
See the doc: https://mongoosejs.com/docs/populate.html
I'm writing a test to check that a function in my Node.js application which returns this JSON structure:
}
id: 1,
name: 'John Doe',
email: 'j#doe.com',
phone: '+123',
suppliers: [
{
id: 1,
name: 'Supplier1'
}
]
}
I have this expect:
expect(res.body.users[0]).to.be.an.instanceof(Object)
.that.includes.all.keys([
'id',
'name',
'suppliers',
]);
I also want to check there are details in suppliers. I could just add this in another expect:
expect(res.body.users[0].suppliers[0]).to.be.an.instanceof(Object)
.that.includes.all.keys([
'id',
'name',
]);
Is it possible to combine both into one expect statement though?
I'm new to ng2-smart-tables. I'm trying modify the example below from the GitHub page so that the check boxes don't disappear when moving from page to page.
import { Component } from '#angular/core';
#Component({
selector: 'basic-example-multi-select',
template: `
<ng2-smart-table [settings]="settings" [source]="data"></ng2-smart-table>
`,
})
export class BasicExampleMultiSelectComponent {
settings = {
selectMode: 'multi',
columns: {
id: {
title: 'ID',
},
name: {
title: 'Full Name',
},
username: {
title: 'User Name',
},
email: {
title: 'Email',
},
},
};
data = [
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere#april.biz',
},
{
id: 2,
name: 'Ervin Howell',
username: 'Antonette',
email: 'Shanna#melissa.tv',
},
{
id: 3,
name: 'Clementine Bauch',
username: 'Samantha',
email: 'Nathan#yesenia.net',
},
{
id: 4,
name: 'Patricia Lebsack',
username: 'Karianne',
email: 'Julianne.OConner#kory.org',
},
{
id: 5,
name: 'Chelsey Dietrich',
username: 'Kamren',
email: 'Lucio_Hettinger#annie.ca',
},
{
id: 6,
name: 'Mrs. Dennis Schulist',
username: 'Leopoldo_Corkery',
email: 'Karley_Dach#jasper.info',
},
{
id: 7,
name: 'Kurtis Weissnat',
username: 'Elwyn.Skiles',
email: 'Telly.Hoeger#billy.biz',
},
{
id: 8,
name: 'Nicholas Runolfsdottir V',
username: 'Maxime_Nienow',
email: 'Sherwood#rosamond.me',
},
{
id: 9,
name: 'Glenna Reichert',
username: 'Delphine',
email: 'Chaim_McDermott#dana.io',
},
{
id: 10,
name: 'Clementina DuBuque',
username: 'Moriah.Stanton',
email: 'Rey.Padberg#karina.biz',
},
{
id: 11,
name: 'Nicholas DuBuque',
username: 'Nicholas.Stanton',
email: 'Rey.Padberg#rosamond.biz',
},
];
}
This uses the selectMode : 'multi'option to show a column with check boxes. The check boxes do show, but every time I use the pagination links to go to another page, the selection is cleared. I'm trying to solve this problem because I have a problem on my project which is analogous to this.
I tried to find documentation on how to persist the selection across pages, but was not successful as only a limited amount of documentation is available. This seems like a feature that's common enough that there should be more information on this out there, but doesn't seem to be the case. Any help on this issue would be greatly appreciated.
I haven't used multi-select with ng2-smart-tables myself, but the documentation mentions
doEmit: boolean - emit event (to refresh the table) or not, default = true
I'm not sure if this will work, but you could try to set this to false.
Create a DataSource from your data and then modify the paginator settings:
source: LocalDataSource;
constructor() {
this.source = new LocalDataSource(this.data);
this.source.setPaging({ doEmit: false });
}
If this doesn't work, you might try adding event-listeners that collect the checked rows on check and re-select them on refresh (or init). Add event callbacks to the table...
<ng2-smart-table [settings]="settings" [source]="source" (rowSelect)="onRowSelect($event)" (userRowSelect)="onUserRowSelect($event)"></ng2-smart-table>
...log the events and see if you get any usable information from there.
onRowSelect(event) {
console.log(event);
}
onUserRowSelect(event) {
console.log(event);
}
If none of this helps, open a new issue on github and hope the developers know an easy way to fix this. :-)
And if that fails too, do what I did and switch to angular/material2. Their documentation sucks, but overall I think it's better than most components out there.
import { LocalDataSource } from 'ng2-smart-table';
settings = {
...
}
data = [
...
]
source: LocalDataSource;
constructor() {
this.source = new LocalDataSource(this.data);
this.source.setPaging(1,10,false);
}
If you want to maintain data along the live of a application, you must save this data in a "persistent way" and use the data saved in the ngOnInit.
In a component, I use ngOnDestroy and a dataService
#Component({
})
export class MyComponent implements OnInit,OnDestroy {}
variable1:number
variable2:number
contructor(private state:MyComponentData)
ngOnInit() {
let data=this.state.Data?data:null;
this.variable1=(data)?data.variable1;
this.variable2=(data)?data.variable2;
}
ngOnDestroy()
{
this.state.Data={
variable1:this.variable1,
variable2:this.variable2
}
}
The service is so easy as
#Injectable()
export class MyComponentData{
Data:any;
}
I want to send a data like this to a rest Webservice :
let params = {
uri: getWsUrl(),
body:queryString.stringify({
city: 885,
customer: user.id,
basket: [
[
product_id: 448025,
count: 2
]
]
})
};
I use request.post(params, function(...)) method for send parameter to Webservice. After sending this request to the server, I get the parameters with $_POST But basket is empty!
Can you help me?
For sending data in response use render, consider the following example
response.end(JSON.stringify({'title': 'Welcome', 'subtitle': "Users List", 'user': result}));
You are trying to send a nested array as if it were an object.
You have two option. Either change the array inside the array to an object.
city: 885,
customer: user.id,
basket: [
{
product_id: 448025,
count: 2
} //HERE
]
}
Or if you really want that array in there (please don't. Try to keep your data as flat as possible.
You can do this (not recommended). Just wrap it in an object
city: 885,
customer: user.id,
basket: [
[{
product_id: 448025,
count: 2
}]
]
}