Related
I have the following Array of data:
{
_id: 5f5726ef7d475a61a95c5e0c,
attributes: [
{
values: [
{ name: '1' }
],
},
{
values: [
{ name: '2' }
]
}
],
attr1: [
{ name: "Study Code" },
{ name: "Patient Study" }
]
}
What I need is to add the correspondent value to each on of attr1 objects based on index. So the result would be:
{
_id: 5f5726ef7d475a61a95c5e0c,
attributes: [
{
values: [
{ name: '1' }
],
},
{
values: [
{ name: '2' }
]
},
],
attr1: [
{
name: "Study Code",
values: [{ name: "1" }]
},
{
name: "Patient Study",
values: [{ name: "2" }]
}
],
}
I wonder if that possible using aggregation $addFields in MongoDB
Query
query works if arrays same size
ziparray to make [[member1_1 member2_1], ....]
map to merge member1_1,member2_1 to a document
Playmongo
aggregate(
[{"$set": {"attr1": {"$zip": {"inputs": ["$attributes", "$attr1"]}}}},
{"$set":
{"attr1":
{"$map":
{"input": "$attr1",
"in":
{"$mergeObjects":
[{"$arrayElemAt": ["$$this", 1]},
{"$arrayElemAt": ["$$this", 0]}]}}}}}])
You can use $zip
db.collection.aggregate([
{
"$project": {
attributes: {
"$zip": {
"inputs": [
"$attributes",
"$attr1"
]
}
}
}
}
])
Here is the Mongo playground for your reference.
i have this array, i want to merge all elements inside the objects in the nested arrays and remove the duplicates..
the array is the output of mongo db populate so answers from there or just js will be amazing :)
"visitors": [
[
{
"name": "matan",
"id": "61793e6a0e08cdcaf213c0b1"
},
{
"name": "shani",
"id": "61793e910e08cdcaf213c0b5"
}
],
[
{
"name": "david",
"id": "6179869cb4944c6b19b05a23"
},
{
"name": "orit",
"id": "617986e535fdf4942ef659bd"
}
],
[
{
"name": "david",
"id": "6179869cb4944c6b19b05a23"
},
{
"name": "orit",
"id": "617986e535fdf4942ef659bd"
}
]
]
would like this output -
"visitors": [
{
"name": "matan",
"id": "61793e6a0e08cdcaf213c0b1"
},
{
"name": "shani",
"id": "61793e910e08cdcaf213c0b5"
},
{
"name": "david",
"id": "6179869cb4944c6b19b05a23"
},
{
"name": "orit",
"id": "617986e535fdf4942ef659bd"
},
]
these are my collections
i need to get all visitors on one solar system,
so > solars > planets > visitors
const solarsModel = new Schema({
planets: [ { type: Schema.Types.ObjectId ,ref:'planet'} ],
starName: { type: String, required: true, default: "" }
})
const planetModel = new Schema({
planetName: { type: String, required: true, default: "" },
system:{type: Schema.Types.ObjectId, ref: 'solar'},
visitors: [{ type: Schema.Types.ObjectId , ref: 'visitor'}]
})
const visitorModel = new Schema({
visitorName:{ type: String, required: true, default: "" },
homePlanet: {type: Schema.Types.ObjectId, ref:"planet" },
visitedPlanets: [{ type: Schema.Types.ObjectId, ref:"planet" }]
})
this is what i did to achieve a result would love to use Aggregate..
const response = await solarModel
.findById({ _id: data.id })
.select({ starName: 1, _id: 0 })
.populate({
path: "planets",
select: { visitors: 1, _id: 0 },
populate: {
path: "visitors",
select: "visitorName",
},
})
.exec();
solved with this
exports.findVisitorSystemHandler = async (data) => {
const systemName = await solarModel.findById({ _id: data.id });
const response = await planetModel.aggregate([
{ $match: { system: makeObjectId(data.id) } },
{
$lookup: {
from: "visitors",
localField: "visitors",
foreignField: "_id",
as: "solarVisitors",
},
},
{
$project: {
solarVisitors: {
visitedPlanets: 0,
homePlanet: 0,
__v: 0,
},
},
},
{ $unwind: "$solarVisitors" },
{
$group: {
_id: null,
system: { $addToSet: systemName.starName },
solarVisitors: {
$addToSet: {
id: "$solarVisitors._id",
name: "$solarVisitors.visitorName",
},
},
},
},
{ $unwind: "$system" },
{
$project: {
_id: 0,
},
},
]);
return response;
};
You can use aggregate() like this:
$unwind twice due to nested array
$group using $addToSet to not get duplicates.
db.collection.aggregate([
{
"$unwind": "$visitors"
},
{
"$unwind": "$visitors"
},
{
"$group": {
"_id": null,
"visitors": {
"$addToSet": {
"id": "$visitors.id",
"name": "$visitors.name"
}
}
}
}
])
Example here
(1) Flatten the array of arrays
visitors = visitors.flat();
Which gives us this:
[
{ name: 'matan', id: '61793e6a0e08cdcaf213c0b1' },
{ name: 'shani', id: '61793e910e08cdcaf213c0b5' },
{ name: 'david', id: '6179869cb4944c6b19b05a23' },
{ name: 'orit', id: '617986e535fdf4942ef659bd' },
{ name: 'david', id: '6179869cb4944c6b19b05a23' },
{ name: 'orit', id: '617986e535fdf4942ef659bd' }
]
(2) Get unique ids
let uniqueIds= [...new Set(visitors.map(v => v.id)]
Which gives us this:
[
'61793e6a0e08cdcaf213c0b1',
'61793e910e08cdcaf213c0b5',
'6179869cb4944c6b19b05a23',
'617986e535fdf4942ef659bd'
]
(3) Get new list of visitors based only on uniqueIds
visitors = uniqueIds.map(id => {
let name = visitors.find(v => v.id === id).name;
return {
id,
name
}
});
Which gives us this:
[
{ name: 'matan', id: '61793e6a0e08cdcaf213c0b1' },
{ name: 'shani', id: '61793e910e08cdcaf213c0b5' },
{ name: 'david', id: '6179869cb4944c6b19b05a23' },
{ name: 'orit', id: '617986e535fdf4942ef659bd' },
]
Query
reduce with concat to flatten
union with an empty array,just to remove duplicates
if you have other fields except visitors they are not affected
PlayMongo
aggregate(
[{"$set":
{"visitors":
{"$setUnion":
[{"$reduce":
{"input": "$visitors",
"initialValue": [],
"in": {"$concatArrays": ["$$value", "$$this"]}}},
[]]}}}])
Results
[{
"visitors": [
{
"name": "david",
"id": "6179869cb4944c6b19b05a23"
},
{
"name": "matan",
"id": "61793e6a0e08cdcaf213c0b1"
},
{
"name": "orit",
"id": "617986e535fdf4942ef659bd"
},
{
"name": "shani",
"id": "61793e910e08cdcaf213c0b5"
}
]
}]
I have category model referencing itself. Below is data of category in mongodb.
{ "_id":{"$oid":"5f55acc029d19e1ac402908f"},
"parents":null,
"name":"pizza",
"slug":"pizza",
"userID":"5f38c867b10f740e38b12198",
"ancestors":[],
}
{ "_id":{"$oid":"5f55b3c0a7b68b3bc0fe16c5"},
"parents":{"$oid":"5f55acc029d19e1ac402908f"},
"name":"premium",
"slug":"premium",
"userID":"5f38c867b10f740e38b12198",
"ancestors":[{
"_id":{"$oid":"5f55acc029d19e1ac402908f"},
"name":"pizza",
"parents":null,
"slug":"pizza",
"depth":{"$numberInt":"0"}
}],
}
{ "_id":{"$oid":"5f55b726b6b12042d09057c2"},
"parents":{"$oid":"5f55b3c0a7b68b3bc0fe16c5"},
"name":"peri peri chicken",
"slug":"peri-peri-chicken",
"userID":"5f38c867b10f740e38b12198",
"ancestors":[{
"_id":{"$oid":"5f55b3c0a7b68b3bc0fe16c5"},
"name":"premium",
"parents":"5f55acc029d19e1ac402908f",
"slug":"premium",
"depth":{"$numberInt":"1"}
},
{
"_id":{"$oid":"5f55acc029d19e1ac402908f"},
"parents":null,
"name":"pizza",
"depth":{"$numberInt":"0"},
"slug":"pizza"
}]
}
{ "_id":{"$oid":"5f55bb8be3088f473c4e15ac"},
"parents":null,
"name":"burger",
"slug":"burger",
"userID":"5f38c867b10f740e38b12198",
"ancestors":[]
}
I have following model in mongoose
const ItemCategorySchema = new Schema({
name: {
type: String,
required: true
},
slug: {
type: String,
index: true
},
parents: {
type: Schema.Types.ObjectId,
default: null,
ref: 'ItemCategory'
},
ancestors: [{
_id: {
type: Schema.Types.ObjectId,
ref: "ItemCategory",
index: true
},
name: { type: String },
parents: { type: String },
slug: { type: String },
depth: { type: Number }
}],
userID: {
type: String,
required: true
}
});
How can I build array like below using the information in ancestors and depth. I am using mongoose. Is there any function in mongoose to populate all category of self referencing into any number of level or depth?
const options = [
{ value: 'pizza', label: 'pizza',
options: [
{ value: 'premium', label: 'premium',
options: [
{ value: 'peri-peri-chicken', label: 'peri peri chicken' },
{ value: 'chicken-and-bacon', label: 'chicken and bacon'},
],
},
{ value: 'traditional', label: 'traditional',
options: [
{ value: 'beef-and-onion', label: 'beef and onion' },
],
},
],
},
{ value: 'burger', label: 'burger',
options: [
{ value: 'chicken', label: 'chicken' },
{ value: 'beef', label: 'beef' },
],
},
]
I have an API call that returns a JSON response object. The shape of the data is bit a confusing and I can't figure out the exact object to run .map() and .filter() on to get my desired result.
.then(response => {
console.log(response); //see below for shape of data
var dataSourceInfo = response.data.included.filter(
element => element.type === "DataSource"
);
var dataSourceName = dataSourceInfo.map(function(included) {
return included["name"];
});
console.log(dataSourceName);
In the two arrays, I'm attempting to filter over response.data.included to find an element by type. Then map over the returned filter to create a new ordered array. In one of the included arrays there is an identifying type of DataSource, here's an example:
included: [
{
id: "2147483604",
type: "DataSource",
name: "Some DataSource"
},
I'm logging the dataSourceName but the array only has the one of the expected names, and it's only from the first array, so it's like the map isn't reaching the second data.data. Any idea how I can get both names to appear in the filtered array?
Edit: correct response object is in the codesandbox
If I understand you correctly, you want a flat list of names where type is "DataSource" given an input that looks like this:
const response = {
data: [
{
data: {
data: {
included: [
{ type: 'DataSource', name: 'First' },
{ type: 'Blah', name: 'Second' },
{ type: 'DataSource', name: 'Third' }
]
}
}
},
{
data: {
data: {
included: [
{ type: 'DataSource', name: 'Fourth' },
{ type: 'Blah', name: 'Fifth' },
{ type: 'DataSource', name: 'Sixth' }
]
}
}
},
]
}
const result = response.data.flatMap(({data: {data: {included}}}) =>
included.reduce((memo, {type, name}) => {
if (type === 'DataSource') {
memo.push(name)
}
return memo;
}, [])
)
console.log(result)
I've omitted parts of the response that aren't relative to the problem
Update:
Here's the code adjusted to work with the responseObject listed in https://codesandbox.io/s/ympo7pr0xx
const responseObject = [ { data: { data: { id: "2147483605", selfUri: "/schedules/2147483605", type: "Schedule", startTime: 1545409610826, status: "InProgress", query: { id: "2147483603", selfUri: "/queries/2147483603", type: "Query" }, dataSource: { id: "2147483604", selfUri: "/datasources/2147483604", type: "DataSource" } }, included: [ { id: "2147483603", selfUri: "/queries/2147483603", type: "Query", name: "Query1", status: "Scheduled", querySchema: { id: "2147483601", selfUri: "/queryschemas/2147483601", type: "QuerySchema" } }, { id: "2147483601", selfUri: "/dataschemas/2147483601", type: "DataSchema", name: "Phone Data" }, { id: "2147483601", selfUri: "/queryschemas/2147483601", type: "QuerySchema", name: "QS1", dataSchema: { id: "2147483601", selfUri: "/dataschemas/2147483601", type: "DataSchema" }, queriesUri: "/queryschemas/2147483601/queries" }, { id: "2147483604", selfUri: "/datasources/2147483604", type: "DataSource", name: "Standalone- 5K", description: "Standalone 5K record" } ] } }, { data: { data: { id: "2147483606", selfUri: "/schedules/2147483606", type: "Schedule", startTime: 1545410049652, status: "Pending", query: { id: "2147483603", selfUri: "/queries/2147483603", type: "Query" }, dataSource: { id: "2147483608", selfUri: "/datasources/2147483608", type: "DataSource" } }, included: [ { id: "2147483608", selfUri: "/datasources/2147483608", type: "DataSource", name: "Standalone 5", description: "Standalone 5 record" }, { id: "2147483603", selfUri: "/queries/2147483603", type: "Query", name: "Query1", status: "Scheduled", querySchema: { id: "2147483601", selfUri: "/queryschemas/2147483601", type: "QuerySchema" }, schedulesUri: "/queries/2147483603/schedules" }, { id: "2147483601", selfUri: "/dataschemas/2147483601", type: "DataSchema", name: "Phone Data" }, { id: "2147483601", selfUri: "/queryschemas/2147483601", type: "QuerySchema", name: "QS1", dataSchema: { id: "2147483601", selfUri: "/dataschemas/2147483601", type: "DataSchema" } } ] } } ];
const result = responseObject.flatMap(({data: {included}}) =>
included.reduce((memo, {type, name}) => {
if (type === 'DataSource') {
memo.push(name)
}
return memo;
}, [])
)
console.log(result)
I have JSON structure as below
var listOfPlays = classRoom: [
{
title: "Dollhouse",
femaleLead: true,
student: [
{ name: "Echo", role: "doll" },
{ name: "Topher", role: "mad scientist" }
]
},
{
title: "Dr. Horrible's Sing-Along Blog",
student: [
{ name: "Billy", role: "mad scientist" },
{ name: "Penny", role: "love interest" }
]
}
]
I know basic about _.where in Underscore.js that it will Looks through each value in the list, returning an array of all the values that contain all of the key-value pairs listed in properties.
For example _.where(listOfPlays, {title: "Dollhouse"}); this will return me an object whose title is "Dollhouse", but how would I get an object base on student array's value? from listOfPlays?
I am looking for something like:
_.where(listOfPlays , {student: [name : "Echo"]});**
The way _.where(listOfPlays , {student: [name : "Echo"]}); you are looking for does not work anymore in the new version.
You can use:
_.filter that looks through each value in the list, returning an array of all the values that pass a truth test (predicate)
_.some that returns true if any of the values in the list pass the predicate truth test.
var listOfPlays = [{
title: "Dollhouse",
femaleLead: true,
student: [{
name: "Echo",
role: "doll"
},
{
name: "Topher",
role: "mad scientist"
}
]
},
{
title: "Dr. Horrible's Sing-Along Blog",
student: [{
name: "Billy",
role: "mad scientist"
},
{
name: "Penny",
role: "love interest"
}
]
}
]
var output = _.filter(listOfPlays, function(item) {
return _.some(item.student, {
name: "Echo"
});
});
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>