I have an user schema in my mongodb database which saves users. In mongoose I write:
const userSchema = new Schema({
email: { type: String, unique: true, lowercase: true},
password: String,
fname: String,
lname: String,
articles: [{
type: Schema.Types.ObjectId,
ref: "article"
}]
})
I've saved a few users to that Collection. When I query my api for users, I get back an array of User objects. Like so:
[
{
"first_name": "Bob",
"_id": "5b36292760afa11b9a216945",
"email": "user#mail.de",
"__v": 0
},
{
"first_name": "Lisa",
"_id": "5bafkjahf123123123123125",
"email": "lisa#mail.de",
"__v": 0
}
]
Is this normal behaviour? And is this coming from the Mongo side of things or the express side? I heard that something like this is more common:
{
"5b36292760afa11b9a216945":{
"first_name": "Bob",
"email": "user#mail.de",
"__v": 0
},
"5bafkjahf123123123123125":
{
"first_name": "Lisa",
"email": "lisa#mail.de",
"__v": 0
}
}
? How could I convert my array into this kind of a JSON? Is there some functionality maybe within mongo that does that for me?
I don't think you can get an object like that back from mongo, but it's not hard to convert it with Array.reduce().
let returnedValue = [{"first_name": "Bob","_id": "5b36292760afa11b9a216945","email": "user#mail.de","__v": 0},{"first_name": "Lisa","_id": "5bafkjahf123123123123125","email": "lisa#mail.de","__v": 0}]
let result = returnedValue.reduce((a, c) => (a[c._id] = c, a), {})
console.log(result)
This leaves the _id in the original object, but if you needed to inside the reduce function.
You can try below aggregation as well
db.collection.aggregate([
{ "$group": {
"_id": null,
"data": {
"$push": {
"k": "$_id",
"v": {
"first_name": "$first_name",
"email": "$email"
}
}
}
}},
{ "$replaceRoot": {
"newRoot": { "$arrayToObject": "$data" }
}}
])
Output
[
{
"5b36292760afa11b9a216945": {
"email": "user#mail.de",
"first_name": "Bob"
},
"5bafkjahf123123123123125": {
"email": "lisa#mail.de",
"first_name": "Lisa"
}
}
]
Related
For example this is the json which I am receiving,
{
"events": [...
],
"total": 12341,
"students": [
{
"id": 1,
"first_name": "John",
"last_name": "Apple"
},
{
"id": 2,
"first_name": "Bob",
"last_name": "Banana"
},
{
"id": 3,
"first_name": "Charles",
"last_name": "Carrot"
}
]
}
And I want to transform the data to the following form, and return it as an observable
[
{
"first_name": "John",
"last_name": "Apple"
},
{
"first_name": "Bob",
"last_name": "Banana"
},
{
"first_name": "Charles",
"last_name": "Carrot"
}
]
I have tried the following, but it returns undefined.
getStudentsName(): Observable<any> {
const requestUrl = this.rootURL + `students/`;
let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));
return studentsInfo.pipe(map(students => {students.first_name, students.last_name}));
}
returns undefined when subscribing to observable
this.getStudentsInfoService.getStudentsName()
.subscribe((result) => console.log('here', result));
It looks like it can't find students. Try this :
return studentsInfo.pipe(map(s => { return {
first_name: s.first_name,
last_name: s.last_name,
}}));
Your problem is, that students is an array, but you handle it as an object. You need to add a nested map: 1 for rxjs, 1 for the array
return studentsInfo.pipe(
map(studentsArray => studentsArray.map(student => ({
first_name: student.first_name,
last_name: student.last_name
}))),
);
PS.: Using types instead of any would have shown you that. Neither you nor the other responders saw this issue due to missing typing.
Here is a short code snippet.
const object = {
"total": 12341,
"students": [
{
"id": 1,
"first_name": "John",
"last_name": "Apple"
},
{
"id": 2,
"first_name": "Bob",
"last_name": "Banana"
},
{
"id": 3,
"first_name": "Charles",
"last_name": "Carrot"
}
]
}
let arr: any = [];
object.students.forEach(person => arr.push(
{
"first_name": person.first_name,
"last_name": person.last_name
}))
console.log(arr)
[LOG]: [{ "first_name": "John", "last_name": "Apple" },
{ "first_name": "Bob", "last_name": "Banana" }, { "first_name": "Charles", "last_name": "Carrot" }]
You can iterate over students with a foreach loop and then create a new json which you then push in your new array
this.http.get<any>(requestUrl).pipe(map(o => o.students.foreach(person => arr.push({
...}));
The Problem
The Problem is with your how you return your observable
Lets break the code down
let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));
In the above studentsInfo will be of type Observable<any>
Next line is as per below
return studentsInfo.pipe(
map(students => {
students.first_name, students.last_name
}
));
Lets have a look at the below section
{
students.first_name, students.last_name
}
This part of the section actually has no return statement hence by default javascript returns undefined!
Solution
To use arrow function without a return statement, you will need to wrap {} inside a () like below
students => ({ })
Below will work
getStudentsName(): Observable<any> {
return this.http.get<any[]>(`${this.routeURL}/students`).pipe(
map(o => o.students));
}
I have an 'users' collection. I store id's of users I follow in 'following' field.
{
"_id": {
"$oid": "5eab360253ec352e3cc791d6"
},
"email": "koray#gmail.com",
"password": "81dc9bdb52d04dc20036dbd8313ed055",
"following": ["5ea8879dfc286e1154a866cb", "5ea8879dfc286e1154a866c"],
"posts": [{
"head": "deneme header",
"body": "deneme body",
"is_private": false
}]
}
I want to get posts of users I follow as well as posts belogs to me but can't manage to pull it off.
You can use $lookup with custom pipeline and fetch documents from the same collection:
db.collection.aggregate([
{ $match: { _id: "5eab360253ec352e3cc791d6" } },
{
$lookup: {
from: "collection",
let: { following_users: "$following" },
pipeline: [
{ $match: { $expr: { $in: [ "$_id", "$$following_users" ] } } },
{ $project: { posts: 1 } }
],
as: "following_posts"
}
}
])
Mongo Playground
I want to transform my data from one json structure to another. What is the best way to do it?
Here is my original resource (customer) structure is:
{
"id": "123",
"data": {
"name": "john doe",
"status": "active",
"contacts": [
{
"email": "john#email.com"
},
{
"phone": "12233333"
}
]
}
}
I want to change it to:
{
"id": "123",
"name": "john doe",
"status": "active",
"contacts": [
{
"email": "john#email.com"
},
{
"phone": "12233333"
}
]
}
Keeping in mind that I might have an array of resources(customers) being returned in GET /customers cases. I want to change that to an array of new data type.
If customer object is array of object then below will help you to get desire format result
var result = customerObj.map(x => {
return {
id: x.id,
name: x.data.name,
status: x.data.status,
contacts: x.data.contacts
};
});
here I have used Object.assign() it will be helpful to you
var arr={
"id": "123",
"data": {
"name": "john doe",
"status": "active",
"contacts": [
{
"email": "john#email.com"
},
{
"phone": "12233333"
}
]
}
}
arr=Object.assign(arr,arr.data);
delete arr['data'];
console.log(arr);
You have to Json.parse the json into variable, and then loop through the array of objects, changes the object to the new format, and then JSON.stringify the array back to json.
Example code
function formatter(oldFormat) {
Object.assign(oldFormat, oldFormat.data);
delete oldFormat.data;
}
let parsedData = JSON.parse(Oldjson);
//Take care for array of results or single result
if (parsedData instanceof Array) {
parsedData.map(customer => formtter(customer));
} else {
formatter(parsedData);
}
let newJson = JSON.stringify(parsedData);
console.log(newJson);
Edit
I made the formatter function cleaner by using Kalaiselvan A code
I need to create a Mongoose model for the below nested JSON array. The issue I am facing is TLSM01 is a dynamic Key and I am unable to specify it in the model. If I mention entities alone and pass all the json objects as string it is storing as [object] and not data.
"entities": [
{
"TLSM01": [
{
"01": {
"Name": "Light",
"Properties": [
{
"state": [
{
"type": "boolean",
"propertyMode": "actuator"
}
],
"brightness": [
{
"type": "integer",
"propertyMode": "actuator"
}
]
}
]
}
}
]
}
Mongoose Model:
var thingsSchema = ({
"uuid": String,
"things": String,
"manufacturerName": String,
"manufacturerId": String,
"osName": String,
"hardwareVersion": String,
"firmwareVersion": String,
"entity": [{String}]
})
Store data in key-value pair
"entities": [
{
keyName:'TLSM01',
data: [
{
"01": {
"Name": "Light",
"Properties": [
{
"state": [
{
"type": "boolean",
"propertyMode": "actuator"
}
],
"brightness": [
{
"type": "integer",
"propertyMode": "actuator"
}
]
}
]
}
}
]
}
]
Mongoose Model:
var thingsSchema = ({
"uuid": String,
"things": String,
"manufacturerName": String,
"manufacturerId": String,
"osName": String,
"hardwareVersion": String,
"firmwareVersion": String,
"entity": [{_id:false,keyName:{type:String},data:[]}]
})
1.I think you need something structured like this:
2.See how the light value is an array...within the object - must use key value paring in Mongo and ensure you model Json Object can be mapped to you mongoose database - hence you use you data model to input data - so this should work if you augment it..
const blogSchema = new Schema({
name:{
type:String,
require: true
},
heat:{
type:Number,
Require:true
},
moisture:{
type:Number,
Require:true
},
light:{
green:{type:Number, Require:true},
red:{type:Number, Require:true},
blue:{type:Number, Require:true},
white:{type:Number, Require:true}
},
body:{
type:String,
require: true
}
},{timeStamps:true});
i know its very simple thing but i m stucked on it
i have json variable with data as follow
var jsonText =
'[ { "user": [ { "Gender": "M", "Minage": "19", "Maxage": "30", "MaritalStatusId":"0", }]
},
{ "user":[ { "maritialtype": "Does not matter" }]
},
{ "user": [ { "Value": "No" }]
} ]';
var jsonObject = JSON.parse(jsonText);
now i can access gender as jsonObject[0].user[0].Gender
but i'm not able to access maritialtype and Value
For maritialtype:
jsonObject[1].user[0].maritialtype
For Value:
jsonObject[2].user[0].Value
Because you have an array of three objects, user, which is an array or one object. It's kind of a weird structure.