阅读(1547) (0)

Moralis 查询

2022-05-11 09:22:53 更新

我们已经看到了带有 ​get ​的 ​Moralis.Query​ 如何从 Moralis 中检索单个 ​Moralis.Object​。 还有许多其他方法可以使用 ​Moralis.Query​ 检索数据。 您可以一次检索多个对象,对要检索的对象设置条件等等。

基本查询

在许多情况下,​get ​功能不足以指定要检索的对象。 ​Moralis.Query​ 提供了不同的方法来检索对象列表,而不仅仅是单个对象。

一般模式是创建一个 ​Moralis.Query​,在其上设置条件,然后使用 ​find ​检索匹配的 ​Moralis.Objects​ 数组。 例如,要检索具有特定 ​ownerName​ 的monster,请使用 ​equalTo ​方法来约束键的值。

你可以使用​JS​、​React​、​Unity​来实现

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
query.equalTo("ownerName", "Aegon");
const results = await query.find();
alert("Successfully retrieved " + results.length + " monsters.");
// Do something with the returned Moralis.Object values
for (let i = 0; i < results.length; i++) {
  const object = results[i];
  alert(object.id + " - " + object.get("ownerName"));
}
import { useMoralisQuery } from "react-moralis";

export default function App() {
  const { fetch } = useMoralisQuery(
    "Monster",
    (query) => query.equalTo("ownerName", "Aegon"),
    [],
    { autoFetch: false }
  );

  const basicQuery = async () => {
    const results = await fetch();
    alert("Successfully retrieved " + results.length + " monsters.");
    // Do something with the returned Moralis.Object values
    for (let i = 0; i < results.length; i++) {
      const object = results[i];
      alert(object.id + " - " + object.get("ownerName"));
    }
  };

  return <button onClick={basicQuery}>Call The Code</button>;
}
using Moralis.Platform.Objects;
using MoralisWeb3ApiSdk;
using Newtonsoft.Json;

 public async void RetrieveObjectFromDB()
    {
        MoralisQuery<Monster> monster = MoralisInterface.GetClient().Query<Monster>().WhereEqualTo("ownerName", "Aegon");
        IEnumerable<Monster> result = await monster.FindAsync();
        foreach(Monster mon in result)
        {
            print("My strength is " + mon.strength + " and can i fly ? " + mon.canFly);
            // output : My strength is 1024 and can i fly ? true
        }
    }

使用主密钥

在某些情况下,查询需要主密钥,

例如,如果您想获取所有用户的列表,您只能使用主密钥在云功能中执行此操作 - 因为由于 ACL,用户无法读取其他用户的信息。

query.find({ useMasterKey: true });

查询约束

有几种方法可以对 ​Moralis.Query​ 找到的对象施加约束。 您可以使用 ​notEqualTo ​过滤掉具有特定键值对的对象:

query.notEqualTo("ownerName", "Daenerys");

您可以提供多个约束,并且对象只有在匹配所有约束时才会出现在结果中。 换句话说,它就像约束的 ​AND​。

query.notEqualTo("ownerName", "Daenerys");
query.greaterThan("ownerAge", 18);

您可以通过设置限制来限制结果的数量。 默认情况下,结果限制为 100。在旧的 Moralis 托管后端中,最大限制为 1,000,但 Moralis Dapps 现在删除了该限制:

query.limit(10); // limit to at most 10 results

如果您只想要一个结果,更方便的替代方法可能是使用​first​而不是使用 ​find​(可以通过​JS​、​React​实现)。

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
query.equalTo("ownerEmail", "daenerys@housetargaryen.com");
const object = await query.first();
import { useMoralisQuery } from "react-moralis";

export default function App() {
  const { fetch } = useMoralisQuery(
    "Monster",
    (query) =>
      query.equalTo("ownerEmail", "daenerys@housetargaryen.com").first(),
    [],
    { autoFetch: false }
  );

  const singleQuery = () =>
    fetch({
      onSuccess: (result) => console.log(result),
    });

  return <button onClick={singleQuery}>Call The Code</button>;
}

您可以通过设置 skip 来跳过第一个结果。 在旧的 Moralis 托管后端中,最大skip值为 10,000,但 Moralis Dapps 现在取消了该限制。 这对于分页很有用:

query.skip(10); // skip the first 10 results

获取满足您查询的表中的总行数,例如 分页目的 - 您可以使用 ​withCount​。

注意:启用此标志将更改响应的结构,请参见下面的示例。

示例 - 假设您在名为 Monster 的表中有 200 行(可以通过​JS​、​React​实现):

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);

query.limit(25);

const results = await query.find(); // [ Monster, Monster, ...]

// to include count:
query.withCount();
const response = await query.find(); // { results: [ Monster, ... ], count: 200 }
const limitQuery = useMoralisQuery("Monster", (query) => query.limit(25), [], {
  autoFetch: false,
});

const getLimitedQuery = () =>
  limitQuery.fetch({
    onSuccess: (result) => console.log(result), // [ Monster, Monster, ...]
  });

const queryCount = useMoralisQuery(
  "Monster",
  (query) => query.withCount(),
  [],
  {
    autoFetch: false,
  }
);

const getQueryWithCount = () =>
  queryCount.fetch({
    onSuccess: (result) => console.log(result), // { results: [ Monster, ... ], count: 200 }
  });

count ​操作可能会很慢而且很昂贵。

如果您只想获取没有对象的计数 - 使用Counting Objects。

要对数字和字符串等可排序类型进行排序,您可以控制返回结果的顺序:

// Sorts the results in ascending order by the strength field
query.ascending("strength");

// Sorts the results in descending order by the strength field
query.descending("strength");

要在可排序类型的查询中进行比较:

// Restricts to wins < 50
query.lessThan("wins", 50);

// Restricts to wins <= 50
query.lessThanOrEqualTo("wins", 50);

// Restricts to wins > 50
query.greaterThan("wins", 50);

// Restricts to wins >= 50
query.greaterThanOrEqualTo("wins", 50);

要检索在值列表中匹配的对象,您可以使用 ​containsIn​,提供可接受值的数组。 这对于用单个查询替换多个查询通常很有用。

例如 - 如果您想检索特定列表中任何monster所有者拥有的monster:

// Finds monsters from any of Jonathan, Dario, or Shawn
query.containedIn("ownerName", [
  "Jonathan Walsh",
  "Dario Wunsch",
  "Shawn Simon",
]);

要检索与多个值中的任何一个都不匹配的对象,您可以使用 ​notContainedIn​,提供一个可接受值的数组。

例如,如果您想从列表中的monster所有者那里检索monster:

// Finds monsters from anyone who is neither Jonathan, Dario, nor Shawn
query.notContainedIn("ownerName", [
  "Jonathan Walsh",
  "Dario Wunsch",
  "Shawn Simon",
]);

要检索具有特定键集的对象,您可以使用 ​exists​。 相反,如果要检索没有特定键集的对象,可以使用 ​doesNotExist​。

// Finds objects that have the strength set
query.exists("strength");

// Finds objects that don't have the strength set
query.doesNotExist("strength");

获取键与另一个查询产生的一组对象中的键值匹配的对象。 您可以使用​matchesKeyInQuery ​方法。

例如,如果您有一个包含运动队的类,并且您在用户类中存储了用户的家乡,则可以发出一次查询以查找家乡球队有获胜记录的用户列表。 查询将如下所示:

const Team = Moralis.Object.extend("Team");
const teamQuery = new Moralis.Query(Team);
teamQuery.greaterThan("winPct", 0.5);
const userQuery = new Moralis.Query(Moralis.User);
userQuery.matchesKeyInQuery("hometown", "city", teamQuery);
// results has the list of users with a hometown team with a winning record
const results = await userQuery.find();

相反,要获取键与另一个查询产生的一组对象中的键值不匹配的对象,请使用 ​doesNotMatchKeyInQuery​。 例如,查找家乡球队有输球记录的用户:

const losingUserQuery = new Moralis.Query(Moralis.User);
losingUserQuery.doesNotMatchKeyInQuery("hometown", "city", teamQuery);
// results has the list of users with a hometown team with a losing record
const results = await losingUserQuery.find();

要根据 ​objectId ​从第二个表中的指针过滤行,可以使用点表示法:

const rolesOfTypeX = new Moralis.Query("Role");
rolesOfTypeX.equalTo("type", "x");

const groupsWithRoleX = new Moralis.Query("Group");
groupsWithRoleX.matchesKeyInQuery(
  "objectId",
  "belongsTo.objectId",
  rolesOfTypeX
);
groupsWithRoleX.find().then(function (results) {
  // results has the list of groups with role x
});

通过使用键列表调用 ​select ​来限制返回的字段。

例如,要检索仅包含 ​strength ​和 ​ownerName ​字段(以及特殊的内置字段,如 ​objectId​、​createdAt ​和 ​updatedAt​)的文档:

你可以通过​JS​、​React​来实现

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
query.select("strength", "ownerName");
query.find().then(function (monsters) {
  // each of the monsters will only have the selected fields available.
});
import { useMoralisQuery } from "react-moralis";

export default function App() {
  const { fetch } = useMoralisQuery(
    "Monster",
    (query) => query.select("strength", "ownerName"),
    [],
    { autoFetch: false }
  );

  const getSelectedQuery = () =>
    fetch({
      onSuccess: (monster) => {
        // each of the monsters will only have the selected fields available.
      },
    });

  return <button onClick={getSelectedQuery}>Call The Code</button>;
}

同样,要在检索其余字段时删除不需要的字段,请使用 ​exclude​(可以通过​JS​、​React​来实现):

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
query.exclude("ownerName");
query.find().then(function (monsters) {
  // Now each monster will have all fields except `ownerName`
});
import { useMoralisQuery } from "react-moralis";

export default function App() {
  const { fetch } = useMoralisQuery(
    "Monster",
    (query) => query.exclude("ownerName"),
    [],
    { autoFetch: false }
  );

  const queryExcludingParam = () =>
    fetch({
      onSuccess: (monsters) => {
        // Now each monster will have all fields except `ownerName`
      },
    });

  return <button onClick={queryExcludingParam}>Call The Code</button>;
}

稍后可以通过对返回的对象调用 ​fetch ​来获取剩余的字段:

query
  .first()
  .then(function (result) {
    // only the selected fields of the object will now be available here.
    return result.fetch();
  })
  .then(function (result) {
    // all fields of the object will now be available here.
  });

请记住在对​address​列进行查询约束时确保​addresses​为小写。

数组值查询

对于数组类型的键,您可以通过以下方式找到键的数组值包含 2 的对象:

// Find objects where the array in arrayKey contains 2.
query.equalTo("arrayKey", 2);

您还可以找到键的数组值包含每个元素 2、3 和 4 的对象,其中包含以下内容:

// Find objects where the array in arrayKey contains all of the elements 2, 3, and 4.
query.containsAll("arrayKey", [2, 3, 4]);

仪表板中的查询测试

注意:可以直接在“​Moralis Dashboard​”中运行查询代码。 可以通过导航到菜单中的“API 控制台 > JS 控制台”找到它。 这是一个在首次构建查询时玩耍的好地方,因为它不需要任何设置或初始化。 它的功能与浏览器中的 JavaScript 控制台完全相同,只是它可以直接访问 Moralis SDK 和主密钥。

完全按照您在客户端或云代码中的方式键入查询。 包括一个 ​console.log()​ 来打印结果,然后按“运行”按钮。 需要注意的一些差异:

  • 需要使用 ​Parse ​关键字而不是 Moralis
    • 即新 ​Parse.Query("EthTokenTransfers")
    • 这可能会在未来的版本中得到修复(Moralis 是 Parse 的一个分支)。
  • 不要在查询中转义 ​$​。
  • 您可以使用主密钥 - ​const results = query.find({ useMasterKey: true })

可以通过单击“保存”在会话之间保存代码。

字符串值查询

从搜索开始

使用 ​startsWith ​限制以特定字符串开头的字符串值。 与 MySQL LIKE 运算符类似,这是索引的,因此对于大型数据集很有效:

// Finds barbecue sauces that start with "Big Daddy's".
const query = new Moralis.Query(BarbecueSauce);
query.startsWith("name", "Big Daddy's");

上面的示例将匹配“name”字符串键中的值以“Big Daddy's”开头的任何 BarbecueSauce 对象。 例如,“Big Daddy's”和“Big Daddy's BBQ”都会匹配,但“big daddy's”或“BBQ Sauce: Big Daddy's”不匹配。

具有正则表达式约束的查询非常昂贵,尤其是对于超过 100,000 条记录的类。 Moralis 限制在任何给定时间可以在特定应用程序上运行的操作数。

全文检索

使用全文以获得高效的搜索功能。 文本索引会自动为您创建。 您的字符串将转换为标记以进行快速搜索。

注意:全文搜索可能是资源密集型的。 确保使用索引的成本物有所值。

const query = new Moralis.Query(BarbecueSauce);
query.fullText("name", "bbq");

上面的示例将匹配“name”字符串键中的值包含“bbq”的任何 BarbecueSauce 对象。 例如,“Big Daddy's BBQ”、“Big Daddy's bbq”和“Big BBQ Daddy”都将匹配。

// You can sort by weight / rank. ascending() and select()
const query = new Moralis.Query(BarbecueSauce);
query.fullText("name", "bbq");
query.ascending("$score");
query.select("$score");
query
  .find()
  .then(function (results) {
    // results contains a weight / rank in result.get('score')
  })
  .catch(function (error) {
    // There was an error.
  });

关系查询

有几种方法可以发出对关系数据的查询。 要检索字段与特定 ​Moralis.Object​ 匹配的对象,您可以使用 ​equalTo​,就像其他数据类型一样。

例如,如果每个 ​Comment ​在其 ​post ​字段中都有一个 ​Post ​对象,您可以获取特定 ​Post ​的评论:

// Assume Moralis.Object myPost was previously created.
const query = new Moralis.Query(Comment);
query.equalTo("post", myPost);
// comments now contains the comments for myPost
const comments = await query.find();

要检索字段包含匹配不同查询的 ​Moralis.Object​ 的对象,您可以使用 ​matchesQuery​。 为了查找包含图片的帖子的评论,您可以执行以下操作:

const Post = Moralis.Object.extend("Post");
const Comment = Moralis.Object.extend("Comment");
const innerQuery = new Moralis.Query(Post);
innerQuery.exists("image");
const query = new Moralis.Query(Comment);
query.matchesQuery("post", innerQuery);
// comments now contains the comments for posts with images.
const comments = await query.find();

要检索字段包含不匹配不同查询的 ​Moralis.Object​ 的对象,您可以使用 ​doesNotMatchQuery​。 要查找没有图片的帖子的评论,您可以执行以下操作:

const Post = Moralis.Object.extend("Post");
const Comment = Moralis.Object.extend("Comment");
const innerQuery = new Moralis.Query(Post);
innerQuery.exists("image");
const query = new Moralis.Query(Comment);
query.doesNotMatchQuery("post", innerQuery);
// comments now contains the comments for posts without images.
const comments = await query.find();

您还可以通过 ​objectId ​进行关系查询:

const post = new Post();
post.id = "1zEcyElZ80";
query.equalTo("post", post);

要在一个查询中返回多种类型的相关对象,请使用 ​include ​方法。

例如,假设您正在检索最后 10 条评论,并且您想同时检索他们的相关帖子:

const query = new Moralis.Query(Comment);

// Retrieve the most recent ones
query.descending("createdAt");

// Only retrieve the last ten
query.limit(10);

// Include the post data with each comment
query.include("post");

// Comments now contains the last ten comments, and the "post" field
const comments = await query.find();
// has been populated. For example:
for (let i = 0; i < comments.length; i++) {
  // This does not require a network access.
  const post = comments[i].get("post");
}

做多级包括使用点符号。 使用以下查询。

例如,如果您想包含评论的帖子和帖子的作者,您可以这样做:

query.include(["post.author"]);

您可以通过多次调用 ​include ​来发出包含多个字段的查询。 此功能也适用于 ​Moralis.Query​ 助手,例如 ​first ​和 ​get​。

计数对象

注意:在旧的 Moralis 托管后端中,计数查询的速率被限制为每分钟最多 160 个请求。 他们还为包含 1,000 多个对象的类返回了不准确的结果。 但是,Moralis Dapp 已经消除了这两个限制,并且可以计算远高于 1,000 个的对象。

要计算有多少对象与查询匹配,但您不需要检索所有匹配的对象,可以使用 ​count ​而不是 ​find​。

例如,要计算特定​monster​拥有者拥有的​monster​数量:

const Monster = Moralis.Object.extend("Monster");
const query = new Moralis.Query(Monster);
query.equalTo("ownerName", "Aegon");
const count = await query.count();
alert("Aegon has owned " + count + " monsters");

复合查询

对于更复杂的查询,您可能需要复合查询。 复合查询是子查询的逻辑组合(例如“and”或“or”)。

注意:我们不支持复合查询的子查询中的 ​GeoPoint ​或非过滤约束(例如 ​near​、​withinGeoBox​、​limit​、​skip​、​ascending/descending​、​include​)。

OR-ed 查询约束

要查找与多个查询之一匹配的对象,您可以使用 ​Moralis.Query.or​ 方法构造一个查询,该查询是传入查询的 ​OR​。

例如,如果您想找到获得很多胜利或少数胜利的玩家,您可以执行以下操作:

const lotsOfWins = new Moralis.Query("Player");
lotsOfWins.greaterThan("wins", 150);

const fewWins = new Moralis.Query("Player");
fewWins.lessThan("wins", 5);

const mainQuery = Moralis.Query.or(lotsOfWins, fewWins);
mainQuery
  .find()
  .then(function (results) {
    // results contains a list of players that either have won a lot of games or won only a few games.
  })
  .catch(function (error) {
    // There was an error.
  });

AND-ed 查询约束

要查找符合所有条件的对象,通常只使用一个查询。 您可以向新创建的 ​Moralis.Query​ 添加额外的约束,充当​and​运算符。

const query = new Moralis.Query("User");
query.greaterThan("age", 18);
query.greaterThan("friends", 0);
query
  .find()
  .then(function (results) {
    // results contains a list of users both older than 18 and having friends.
  })
  .catch(function (error) {
    // There was an error.
  });

有时比这个简单的示例更复杂,您可能需要子查询的复合查询。 您可以使用 ​Moralis.Query.and​ 方法构造一个查询,该查询是传入查询的 ​AND​。

例如,如果您想查找 16 岁或 18 岁且没有朋友或至少有两个朋友的用户,您可以执行以下操作:

const age16Query = new Moralis.Query("User");
age16Query.equalTo("age", 16);

const age18Query = new Moralis.Query("User");
age18Query.equalTo("age", 18);

const friends0Query = new Moralis.Query("User");
friends0Query.equalTo("friends", 0);

const friends2Query = new Moralis.Query("User");
friends2Query.greaterThan("friends", 2);

const mainQuery = Moralis.Query.and(
  Moralis.Query.or(age16Query, age18Query),
  Moralis.Query.or(friends0Query, friends2Query)
);
mainQuery
  .find()
  .then(function (results) {
    // results contains a list of users in the age of 16 or 18 who have either no friends or at least 2 friends
    // results: (age 16 or 18) and (0 or >2 friends)
  })
  .catch(function (error) {
    // There was an error.
  });

总计的

可以使用聚合进行查询,允许您通过一组输入值检索对象。 结果不会是 ​Moralis.Objects​,因为您将聚合自己的字段。

MasterKey ​是必需的。

聚合使用阶段通过将结果从一个阶段传递到下一个阶段来过滤结果。 前一阶段的输出成为下一阶段的输入。

您可以使用数组或对象创建管道。

const pipelineObject = {
  group: { objectId: "$name" },
};

const pipelineArray = [{ group: { objectId: "$name" } }];

有关可用阶段的列表,请参阅 Mongo 聚合文档

注意:Mongo 聚合文档中的大多数操作都适用于 ​Moralis Server​,但 ​_id​ 不存在。 请替换为 ​objectId​。

Match

Match管道类似于equalTo。

const pipeline = [{ match: { name: "BBQ" } }];

const query = new Moralis.Query("User");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains name that matches 'BBQ'
  })
  .catch(function (error) {
    // There was an error.
  });

您可以通过比较来匹配。

const pipeline = [{ match: { score: { $gt: 15 } } }];

const query = new Moralis.Query("User");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains score greater than 15
  })
  .catch(function (error) {
    // There was an error.
  });

您可以在 Mongo 查询运算符文档中阅读有关可用运算符的更多信息。

Lookup (Join)

lookup管道类似于 SQL 中的 LEFT OUTER JOIN。 它将匹配另一个集合中的文档并将它们作为数组属性带入结果中。 

例如,在投资组合应用程序中,您可能希望显示用户的所有代币交易。 在 Moralis 中,这些存储在 ​EthTokenTransfers ​集合中。 除了令牌名称和小数位数之外,此集合包含所需的所有信息,这些信息是在前端以一种很好的方式显示此信息所必需的。 额外的信息在 ​EthTokenBalance ​集合中,为了得到它,我们需要查找。 有关更多详细信息,请查看 Mongo lookup文档

简单查找(单等式)

不幸的是,对于我们的用例,​EthTokenBalance ​集合不仅包含我们当前用户的信息,还包含所有用户的信息。 这意味着每个持有该令牌的用户都会重复该令牌名称。 这意味着加入多个属性,它需要不同的语法,下面将介绍。 现在,假设我们有另一个名为 ​Token ​的集合,它看起来像这样:

Token {
  objectId: string,
  token_address: string,
  symbol: string,
  name: string,
  decimals: number
}

然后你会定义一个这样的云函数(聚合查询必须在云代码中运行)。

记住要像 ​\$​ 一样转义 ​$​ 以防止解析错误(现在已修复!)。

// this goes in the Moralis server Cloud Functions section
Moralis.Cloud.define("getUserTokenTransfers", function (request) {
  const userAddress = request.params.userAddress;
  const query = new Moralis.Query("EthTokenTransfers");

  const pipeline = [
    // only transfers to or from userAddress
    {
      match: {
        $expr: {
          $or: [
            { $eq: ["$from_address", userAddress] },
            { $eq: ["$to_address", userAddress] },
          ],
        },
      },
    },

    // join to Token collection on token_address
    {
      lookup: {
        from: "Token",
        localField: "token_address",
        foreignField: "token_address",
        as: "token",
      },
    },
  ];

  return query.aggregate(pipeline);
});

输出如下所示: “​token​”指定 ​Token ​表中匹配文档的输出数组的名称。 如果连接是一对多而不是一对一,则此数组的长度将大于 1。

[
  {
    // EthTokenTransfer collection attributes
    "block_timestamp":{...}
    "token_address": "0x8762db106b2c2a0bccb3a80d1ed41273552616e8"
    "from_address": "0xba65016890709dbc9491ca7bf5de395b8441dc8b"
    "to_address": "0x29781d9fca70165cbc952b8c558d528b85541f0b"
    "value": "29803465370630263212090"
    "transaction_hash": "0xfc611dbae7c67cd938fca58a0cc2fe46d224f71b91472d4c9241e997e6440ac1"
    "token": [
      {
        // Token collection attributes from lookup
        "_id": "HKA8dzHG1A"
        "token_address": "0x8762db106b2c2a0bccb3a80d1ed41273552616e8"
        "symbol": "RSR"
        "name": "Reserve Rights"
        "decimals": 18
      }
    ]
  }
]

复杂连接(多重相等)

连接多个属性需要在查找中使用嵌套管道,但在定义集合应如何连接时提供了更大的灵活性。 上面的查询可以重写以加入 ​EthTokenTranfers ​和 ​EthTokenBalance​。

// this goes in the Moralis server Cloud Functions section
Moralis.Cloud.define("getUserTokenTransfers", function(request) {
  const userAddress = request.params.userAddress;
  const query = new Moralis.Query("EthTokenTransfers");

  const pipeline = [
    // only transfers to or from userAddress
    {match: {$expr: {$or: [
      {$eq: ["$from_address", userAddress]},
      {$eq: ["$to_address", userAddress]},
    ]}}},

      // join to EthTokenBalance on token_address and userAddress
    {lookup: {
      from: "EthTokenBalance",
      let: { tokenAddress: "$token_address", userAddress: userAddress},
      pipeline: [
        {$match: {$expr: {$and: [
          { $eq: ["$token_address", "$tokenAddress"] },
          { $eq: ["$address", "$userAddress"] },
      ]}}],
      as: "EthTokenBalance",
    }}
  ];

  return query.aggregate(pipeline);
});

lookup管道使用匹配阶段来指定其他连接条件。 另外,请注意 let 定义了查找管道要使用的变量。 这是必需的,因为查找管道无法直接访问原始集合中的属性。 有关详细信息,请参阅 MongoDB $lookup 文档中的“使用 $lookup 指定多个连接条件”部分。

项目(选择)

项目管道类似于键或选择、添加或删除现有字段。

const pipeline = [{ project: { name: 1 } }];

const query = new Moralis.Query("User");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains only name field
  })
  .catch(function (error) {
    // There was an error.
  });

Group

组管道类似于不同的。

您可以按字段分组:

// score is the field. $ before score lets the database know this is a field
const pipeline = [{ group: { objectId: "$score" } }];

const query = new Moralis.Query("User");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains unique score values
  })
  .catch(function (error) {
    // There was an error.
  });

您可以应用集体计算,如 $sum、$avg、$max、$min。

// total will be a newly created field to hold the sum of score field
const pipeline = [{ group: { objectId: null, total: { $sum: "$score" } } }];

const query = new Moralis.Query("User");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains sum of score field and stores it in results[0].total
  })
  .catch(function (error) {
    // There was an error.
  });

如果要对包含数值但它们作为字符串存储在数据库中的列执行计算,则必须将值转换为数值数据类型。 例如,存储在字符串列中的 uint256 应使用 ​$toLong​ 进行转换。

 { group: { objectId: '$nftItem',  priceOfAllNfts: { $sum: {$toLong : '$price'} } } },

可以使用 ​$$ROOT​ 访问与分组字段匹配的文档集合,并且可以使用 ​$push​ 累加器将其推送到数组中。

// games will be an array of all the games played by each unique player
const pipeline = [
  { group: { objectId: "$playerId", games: { $push: "$ROOT" } } },
];

const query = new Moralis.Query("GameRound");

query
  .aggregate(pipeline)
  .then(function (results) {
    // results contains a collection of players with their respective games played
  })
  .catch(function (error) {
    // There was an error.
  });

您可以使用点表示法按子文档的列进行分组。 但是,您必须将其括在引号中。

 { group: { objectId: '$player.username',  games: { $push: "$ROOT" } } },

Sort

排序阶段用于按给定列按特定顺序对结果进行排序。

指定排序顺序,1 用于升序排序,-1 用于降序排序。

// This will sort the rows in ascending order based on the username field
{
  sort: {
    username: 1;
  }
}

您可以按给定顺序按几列排序。

 // This will sort the rows in ascending order based on the country field,
 // and then in descending order on the city field
 { sort : { country: 1, city: -1 } }

skip

跳过阶段跳过传递到该阶段的指定行数。 这通常在实现分页功能时使用。

// This stage will skip the first 5 rows passed into this stage
{
  skip: 5;
}

Limit

限制阶段仅包括传入该阶段的前 n 行。

// This stage will throw away all rows except the first 5
{
  limit: 5;
}

Count

count 阶段返回传递到分配给变量名称的阶段的行数。

// This stage will return the number of rows passed into the stage
// and store it in the variable numberOfNfts
{
  count: "numberOfNfts";
}

Distinct

可以使用 distinct 进行查询,允许您找到指定字段的唯一值。

MasterKey ​是必需的。

const query = new Moralis.Query("User");

query
  .distinct("age")
  .then(function (results) {
    // results contains unique age
  })
  .catch(function (error) {
    // There was an error.
  });

您还可以使用 ​equalTo ​限制结果。

const query = new Moralis.Query("User");
query.equalTo("name", "foo");
query
  .distinct("age")
  .then(function (results) {
    // results contains unique age where name is foo
  })
  .catch(function (error) {
    // There was an error.
  });

阅读偏好

使用 MongoDB 副本集时,您可以使用 ​query.readPreference(readPreference, includeReadPreference, subqueryReadPreference)​ 函数来选择将从哪个副本中检索对象。 ​includeReadPreference ​参数选择从哪个副本中检索包含的指针,而 ​subqueryReadPreference ​参数选择子查询将在哪个副本中运行。 可能的值为 ​PRIMARY​(默认)、​PRIMARY_PREFERRED​、​SECONDARY​、​SECONDARY_PREFERRED ​或 ​NEAREST​。 如果未传递 ​includeReadPreference ​参数,则为 ​readPreference ​选择的相同副本也将用于包含。 相同的规则适用于 ​subqueryReadPreference ​参数。

query.readPreference("SECONDARY", "SECONDARY_PREFERRED", "NEAREST");